0001: /*
0002: * ============================================================================
0003: * GNU Lesser General Public License
0004: * ============================================================================
0005: *
0006: * JasperReports - Free Java report-generating library.
0007: * Copyright (C) 2001-2006 JasperSoft Corporation http://www.jaspersoft.com
0008: *
0009: * This library is free software; you can redistribute it and/or
0010: * modify it under the terms of the GNU Lesser General Public
0011: * License as published by the Free Software Foundation; either
0012: * version 2.1 of the License, or (at your option) any later version.
0013: *
0014: * This library is distributed in the hope that it will be useful,
0015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0017: * Lesser General Public License for more details.
0018: *
0019: * You should have received a copy of the GNU Lesser General Public
0020: * License along with this library; if not, write to the Free Software
0021: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
0022: *
0023: * JasperSoft Corporation
0024: * 303 Second Street, Suite 450 North
0025: * San Francisco, CA 94107
0026: * http://www.jaspersoft.com
0027: */
0028:
0029: /*
0030: * Special thanks to Google 'Summer of Code 2005' program for supporting this development
0031: *
0032: * Contributors:
0033: * Majid Ali Khan - majidkk@users.sourceforge.net
0034: * Frank Schönheit - Frank.Schoenheit@Sun.COM
0035: */
0036: package net.sf.jasperreports.engine.export.oasis;
0037:
0038: import java.awt.Color;
0039: import java.awt.Dimension;
0040: import java.awt.geom.Dimension2D;
0041: import java.io.File;
0042: import java.io.FileOutputStream;
0043: import java.io.IOException;
0044: import java.io.OutputStream;
0045: import java.io.Writer;
0046: import java.text.AttributedCharacterIterator;
0047: import java.util.ArrayList;
0048: import java.util.HashMap;
0049: import java.util.Iterator;
0050: import java.util.LinkedList;
0051: import java.util.List;
0052: import java.util.Map;
0053:
0054: import net.sf.jasperreports.engine.JRAbstractExporter;
0055: import net.sf.jasperreports.engine.JRAlignment;
0056: import net.sf.jasperreports.engine.JRElement;
0057: import net.sf.jasperreports.engine.JRException;
0058: import net.sf.jasperreports.engine.JRExporterParameter;
0059: import net.sf.jasperreports.engine.JRImage;
0060: import net.sf.jasperreports.engine.JRImageRenderer;
0061: import net.sf.jasperreports.engine.JRLine;
0062: import net.sf.jasperreports.engine.JRPrintElement;
0063: import net.sf.jasperreports.engine.JRPrintElementIndex;
0064: import net.sf.jasperreports.engine.JRPrintEllipse;
0065: import net.sf.jasperreports.engine.JRPrintFrame;
0066: import net.sf.jasperreports.engine.JRPrintImage;
0067: import net.sf.jasperreports.engine.JRPrintLine;
0068: import net.sf.jasperreports.engine.JRPrintPage;
0069: import net.sf.jasperreports.engine.JRPrintRectangle;
0070: import net.sf.jasperreports.engine.JRPrintText;
0071: import net.sf.jasperreports.engine.JRRenderable;
0072: import net.sf.jasperreports.engine.JRRuntimeException;
0073: import net.sf.jasperreports.engine.JRWrappingSvgRenderer;
0074: import net.sf.jasperreports.engine.JasperPrint;
0075: import net.sf.jasperreports.engine.export.JRExportProgressMonitor;
0076: import net.sf.jasperreports.engine.export.JRExporterGridCell;
0077: import net.sf.jasperreports.engine.export.JRGridLayout;
0078: import net.sf.jasperreports.engine.export.JRHyperlinkProducerFactory;
0079: import net.sf.jasperreports.engine.export.oasis.zip.FileBufferedOasisZip;
0080: import net.sf.jasperreports.engine.export.oasis.zip.FileBufferedOasisZipEntry;
0081: import net.sf.jasperreports.engine.export.oasis.zip.OasisZip;
0082: import net.sf.jasperreports.engine.export.oasis.zip.OasisZipEntry;
0083: import net.sf.jasperreports.engine.util.JRProperties;
0084: import net.sf.jasperreports.engine.util.JRStringUtil;
0085: import net.sf.jasperreports.engine.util.JRStyledText;
0086:
0087: /**
0088: * Exports a JasperReports document to ODF format. It has character output type and exports the document to a
0089: * grid-based layout.
0090: * @author Teodor Danciu (teodord@users.sourceforge.net)
0091: * @version $Id: JROdtExporter.java 1824 2007-08-23 14:19:12Z teodord $
0092: */
0093: public class JROdtExporter extends JRAbstractExporter {
0094:
0095: /**
0096: *
0097: */
0098: protected static final String JR_PAGE_ANCHOR_PREFIX = "JR_PAGE_ANCHOR_";
0099:
0100: /**
0101: *
0102: */
0103: protected static final String HORIZONTAL_ALIGN_LEFT = "start";
0104: protected static final String HORIZONTAL_ALIGN_RIGHT = "end";
0105: protected static final String HORIZONTAL_ALIGN_CENTER = "center";
0106: protected static final String HORIZONTAL_ALIGN_JUSTIFY = "justified";
0107:
0108: /**
0109: *
0110: */
0111: protected static final String VERTICAL_ALIGN_TOP = "top";
0112: protected static final String VERTICAL_ALIGN_MIDDLE = "middle";
0113: protected static final String VERTICAL_ALIGN_BOTTOM = "bottom";
0114:
0115: public static final String IMAGE_NAME_PREFIX = "img_";
0116: protected static final int IMAGE_NAME_PREFIX_LEGTH = IMAGE_NAME_PREFIX
0117: .length();
0118:
0119: /**
0120: *
0121: */
0122: protected Writer tempBodyWriter = null;
0123: protected Writer tempStyleWriter = null;
0124:
0125: protected JRExportProgressMonitor progressMonitor = null;
0126: protected Map rendererToImagePathMap = null;
0127: protected Map imageMaps;
0128: protected List imagesToProcess = null;
0129:
0130: protected int reportIndex = 0;
0131: protected int pageIndex = 0;
0132: protected int tableIndex = 0;
0133:
0134: /**
0135: *
0136: */
0137: protected String encoding = null;
0138:
0139: /**
0140: *
0141: */
0142: protected boolean isWrapBreakWord = false;
0143:
0144: protected Map fontMap = null;
0145:
0146: private LinkedList backcolorStack;
0147: private Color backcolor;
0148:
0149: private StyleCache styleCache = null;
0150:
0151: protected JRHyperlinkProducerFactory hyperlinkProducerFactory;
0152:
0153: public JROdtExporter() {
0154: backcolorStack = new LinkedList();
0155: backcolor = null;
0156: }
0157:
0158: /**
0159: *
0160: */
0161: public void exportReport() throws JRException {
0162: progressMonitor = (JRExportProgressMonitor) parameters
0163: .get(JRExporterParameter.PROGRESS_MONITOR);
0164:
0165: /* */
0166: setOffset();
0167:
0168: try {
0169: /* */
0170: setExportContext();
0171:
0172: /* */
0173: setInput();
0174:
0175: /* */
0176: if (!isModeBatch) {
0177: setPageRange();
0178: }
0179:
0180: encoding = getStringParameter(
0181: JRExporterParameter.CHARACTER_ENCODING,
0182: JRExporterParameter.PROPERTY_CHARACTER_ENCODING);
0183: encoding = encoding == null ? JRProperties
0184: .getProperty(JRExporterParameter.PROPERTY_CHARACTER_ENCODING)
0185: : encoding;
0186:
0187: rendererToImagePathMap = new HashMap();
0188: imageMaps = new HashMap();
0189: imagesToProcess = new ArrayList();
0190:
0191: fontMap = (Map) parameters
0192: .get(JRExporterParameter.FONT_MAP);
0193:
0194: setHyperlinkProducerFactory();
0195:
0196: OutputStream os = (OutputStream) parameters
0197: .get(JRExporterParameter.OUTPUT_STREAM);
0198: if (os != null) {
0199: try {
0200: exportReportToOasisZip(os);
0201: } catch (IOException e) {
0202: throw new JRException(
0203: "Error trying to export to output stream : "
0204: + jasperPrint.getName(), e);
0205: }
0206: } else {
0207: File destFile = (File) parameters
0208: .get(JRExporterParameter.OUTPUT_FILE);
0209: if (destFile == null) {
0210: String fileName = (String) parameters
0211: .get(JRExporterParameter.OUTPUT_FILE_NAME);
0212: if (fileName != null) {
0213: destFile = new File(fileName);
0214: } else {
0215: throw new JRException(
0216: "No output specified for the exporter.");
0217: }
0218: }
0219:
0220: try {
0221: os = new FileOutputStream(destFile);
0222: exportReportToOasisZip(os);
0223: } catch (IOException e) {
0224: throw new JRException(
0225: "Error trying to export to file : "
0226: + destFile, e);
0227: } finally {
0228: if (os != null) {
0229: try {
0230: os.close();
0231: } catch (IOException e) {
0232: }
0233: }
0234: }
0235: }
0236: } finally {
0237: resetExportContext();
0238: }
0239: }
0240:
0241: protected void setHyperlinkProducerFactory() {
0242: hyperlinkProducerFactory = (JRHyperlinkProducerFactory) parameters
0243: .get(JRExporterParameter.HYPERLINK_PRODUCER_FACTORY);
0244: }
0245:
0246: /**
0247: *
0248: */
0249: public static JRPrintImage getImage(List jasperPrintList,
0250: String imageName) {
0251: return getImage(jasperPrintList,
0252: getPrintElementIndex(imageName));
0253: }
0254:
0255: public static JRPrintImage getImage(List jasperPrintList,
0256: JRPrintElementIndex imageIndex) {
0257: JasperPrint report = (JasperPrint) jasperPrintList
0258: .get(imageIndex.getReportIndex());
0259: JRPrintPage page = (JRPrintPage) report.getPages().get(
0260: imageIndex.getPageIndex());
0261:
0262: Integer[] elementIndexes = imageIndex.getAddressArray();
0263: Object element = page.getElements().get(
0264: elementIndexes[0].intValue());
0265:
0266: for (int i = 1; i < elementIndexes.length; ++i) {
0267: JRPrintFrame frame = (JRPrintFrame) element;
0268: element = frame.getElements().get(
0269: elementIndexes[i].intValue());
0270: }
0271:
0272: return (JRPrintImage) element;
0273: }
0274:
0275: /**
0276: *
0277: */
0278: protected void exportReportToOasisZip(OutputStream os)
0279: throws JRException, IOException {
0280: OasisZip oasisZip = new FileBufferedOasisZip();
0281:
0282: OasisZipEntry tempBodyEntry = new FileBufferedOasisZipEntry(
0283: null);
0284: OasisZipEntry tempStyleEntry = new FileBufferedOasisZipEntry(
0285: null);
0286:
0287: tempBodyWriter = tempBodyEntry.getWriter();
0288: tempStyleWriter = tempStyleEntry.getWriter();
0289:
0290: styleCache = new StyleCache(tempStyleWriter, fontMap);
0291:
0292: Writer stylesWriter = oasisZip.getStylesEntry().getWriter();
0293:
0294: StyleBuilder styleBuilder = new StyleBuilder(jasperPrintList,
0295: stylesWriter);
0296: styleBuilder.build();
0297:
0298: stylesWriter.close();
0299:
0300: for (reportIndex = 0; reportIndex < jasperPrintList.size(); reportIndex++) {
0301: jasperPrint = (JasperPrint) jasperPrintList
0302: .get(reportIndex);
0303:
0304: List pages = jasperPrint.getPages();
0305: if (pages != null && pages.size() > 0) {
0306: if (isModeBatch) {
0307: startPageIndex = 0;
0308: endPageIndex = pages.size() - 1;
0309: }
0310:
0311: JRPrintPage page = null;
0312: for (pageIndex = startPageIndex; pageIndex <= endPageIndex; pageIndex++) {
0313: if (Thread.currentThread().isInterrupted()) {
0314: throw new JRException(
0315: "Current thread interrupted.");
0316: }
0317:
0318: page = (JRPrintPage) pages.get(pageIndex);
0319:
0320: exportPage(page);
0321: }
0322: }
0323: }
0324:
0325: tempBodyWriter.flush();
0326: tempStyleWriter.flush();
0327:
0328: tempBodyWriter.close();
0329: tempStyleWriter.close();
0330:
0331: /* */
0332: ContentBuilder contentBuilder = new ContentBuilder(oasisZip
0333: .getContentEntry(), tempStyleEntry, tempBodyEntry,
0334: styleCache.getFontFaces());
0335: contentBuilder.build();
0336:
0337: tempStyleEntry.dispose();
0338: tempBodyEntry.dispose();
0339:
0340: if ((imagesToProcess != null && imagesToProcess.size() > 0)) {
0341: for (Iterator it = imagesToProcess.iterator(); it.hasNext();) {
0342: JRPrintElementIndex imageIndex = (JRPrintElementIndex) it
0343: .next();
0344:
0345: JRPrintImage image = getImage(jasperPrintList,
0346: imageIndex);
0347: JRRenderable renderer = image.getRenderer();
0348: if (renderer.getType() == JRRenderable.TYPE_SVG) {
0349: renderer = new JRWrappingSvgRenderer(
0350: renderer,
0351: new Dimension(image.getWidth(), image
0352: .getHeight()),
0353: JRElement.MODE_OPAQUE == image.getMode() ? image
0354: .getBackcolor()
0355: : null);
0356: }
0357:
0358: oasisZip.addEntry(//FIXMEODT optimize with a different implementation of entry
0359: new FileBufferedOasisZipEntry("Pictures/"
0360: + getImageName(imageIndex), renderer
0361: .getImageData()));
0362: }
0363: }
0364:
0365: oasisZip.zipEntries(os);
0366:
0367: oasisZip.dispose();
0368: }
0369:
0370: /**
0371: *
0372: */
0373: protected void exportPage(JRPrintPage page) throws JRException,
0374: IOException {
0375: JRGridLayout layout = new JRGridLayout(JROdtExporterNature
0376: .getInstance(), page.getElements(), jasperPrint
0377: .getPageWidth(), jasperPrint.getPageHeight(),
0378: globalOffsetX, globalOffsetY, null //address
0379: );
0380:
0381: exportGrid(layout, null);
0382:
0383: if (progressMonitor != null) {
0384: progressMonitor.afterPageExport();
0385: }
0386: }
0387:
0388: /**
0389: *
0390: */
0391: protected void exportGrid(JRGridLayout gridLayout,
0392: JRPrintElementIndex frameIndex) throws IOException,
0393: JRException {
0394: List xCuts = gridLayout.getXCuts();
0395: JRExporterGridCell[][] grid = gridLayout.getGrid();
0396:
0397: TableBuilder tableBuilder = frameIndex == null ? new TableBuilder(
0398: reportIndex, pageIndex, tempBodyWriter, tempStyleWriter)
0399: : new TableBuilder(frameIndex.toString(),
0400: tempBodyWriter, tempStyleWriter);
0401:
0402: tableBuilder.buildTableStyle();
0403: tableBuilder.buildTableHeader();
0404:
0405: for (int col = 1; col < xCuts.size(); col++) {
0406: tableBuilder.buildColumnStyle(col - 1, ((Integer) xCuts
0407: .get(col)).intValue()
0408: - ((Integer) xCuts.get(col - 1)).intValue());
0409: tableBuilder.buildColumnHeader(col - 1);
0410: tableBuilder.buildColumnFooter();
0411: }
0412:
0413: JRPrintElement element = null;
0414: for (int row = 0; row < grid.length; row++) {
0415: //JRExporterGridCell[] gridRow = grid[row];
0416:
0417: int emptyCellColSpan = 0;
0418: int emptyCellWidth = 0;
0419: int rowHeight = gridLayout.getRowHeight(row);
0420:
0421: tableBuilder.buildRowStyle(row, rowHeight);
0422: tableBuilder.buildRowHeader(row);
0423:
0424: for (int col = 0; col < grid[0].length; col++) {
0425: JRExporterGridCell gridCell = grid[row][col];
0426: if (gridCell == JRExporterGridCell.OCCUPIED_CELL) {
0427: if (emptyCellColSpan > 0) {
0428: writeEmptyCell(gridCell, emptyCellColSpan,
0429: emptyCellWidth, rowHeight);
0430: emptyCellColSpan = 0;
0431: emptyCellWidth = 0;
0432: }
0433:
0434: writeOccupiedCells(1);
0435: } else if (gridCell.getWrapper() != null) {
0436: if (emptyCellColSpan > 0) {
0437: writeEmptyCell(gridCell, emptyCellColSpan,
0438: emptyCellWidth, rowHeight);
0439: emptyCellColSpan = 0;
0440: emptyCellWidth = 0;
0441: }
0442:
0443: element = gridCell.getWrapper().getElement();
0444:
0445: if (element instanceof JRPrintLine) {
0446: exportLine(tableBuilder, (JRPrintLine) element,
0447: gridCell);
0448: } else if (element instanceof JRPrintRectangle) {
0449: exportRectangle(tableBuilder,
0450: (JRPrintRectangle) element, gridCell);
0451: } else if (element instanceof JRPrintEllipse) {
0452: exportEllipse(tableBuilder,
0453: (JRPrintEllipse) element, gridCell);
0454: } else if (element instanceof JRPrintImage) {
0455: exportImage(tableBuilder,
0456: (JRPrintImage) element, gridCell);
0457: } else if (element instanceof JRPrintText) {
0458: exportText(tableBuilder, (JRPrintText) element,
0459: gridCell);
0460: } else if (element instanceof JRPrintFrame) {
0461: exportFrame(tableBuilder,
0462: (JRPrintFrame) element, gridCell);
0463: }
0464:
0465: //x += gridCell.colSpan - 1;
0466: } else {
0467: emptyCellColSpan++;
0468: emptyCellWidth += gridCell.getWidth();
0469: }
0470: }
0471:
0472: if (emptyCellColSpan > 0) {
0473: writeEmptyCell(null, emptyCellColSpan, emptyCellWidth,
0474: rowHeight);
0475: }
0476:
0477: tableBuilder.buildRowFooter();
0478: }
0479:
0480: tableBuilder.buildTableFooter();
0481: }
0482:
0483: private void writeEmptyCell(JRExporterGridCell gridCell,
0484: int emptyCellColSpan, int emptyCellWidth, int rowHeight)
0485: throws IOException {
0486: tempBodyWriter.write("<table:table-cell");
0487: //tempBodyWriter.write(" office:value-type=\"string\"");
0488: tempBodyWriter.write(" table:style-name=\"empty-cell\"");
0489: if (emptyCellColSpan > 1) {
0490: tempBodyWriter.write(" table:number-columns-spanned=\""
0491: + emptyCellColSpan + "\"");
0492: }
0493: tempBodyWriter.write("/>\n");
0494:
0495: writeOccupiedCells(emptyCellColSpan - 1);
0496: }
0497:
0498: private void writeOccupiedCells(int count) throws IOException {
0499: for (int i = 0; i < count; i++) {
0500: tempBodyWriter.write("<table:covered-table-cell/>\n");
0501: }
0502: }
0503:
0504: /**
0505: *
0506: */
0507: protected void exportLine(TableBuilder tableBuilder,
0508: JRPrintLine line, JRExporterGridCell gridCell)
0509: throws IOException {
0510: tableBuilder.buildCellHeader(null, gridCell.getColSpan(),
0511: gridCell.getRowSpan());
0512:
0513: double x1, y1, x2, y2;
0514:
0515: if (line.getDirection() == JRLine.DIRECTION_TOP_DOWN) {
0516: x1 = Utility.translatePixelsToInches(0);
0517: y1 = Utility.translatePixelsToInches(0);
0518: x2 = Utility.translatePixelsToInches(line.getWidth() - 1);
0519: y2 = Utility.translatePixelsToInches(line.getHeight() - 1);
0520: } else {
0521: x1 = Utility.translatePixelsToInches(0);
0522: y1 = Utility.translatePixelsToInches(line.getHeight() - 1);
0523: x2 = Utility.translatePixelsToInches(line.getWidth() - 1);
0524: y2 = Utility.translatePixelsToInches(0);
0525: }
0526:
0527: tempBodyWriter.write("<text:p "
0528: // + "text:style-name=\"Standard\""
0529: + ">" + "<draw:line text:anchor-type=\"paragraph\" "
0530: + "draw:style-name=\""
0531: + styleCache.getGraphicStyle(line) + "\" "
0532: + "svg:x1=\"" + x1 + "in\" " + "svg:y1=\"" + y1
0533: + "in\" " + "svg:x2=\"" + x2 + "in\" " + "svg:y2=\""
0534: + y2 + "in\">"
0535: //+ "</draw:line>"
0536: + "<text:p/></draw:line>" + "</text:p>");
0537: tableBuilder.buildCellFooter();
0538: }
0539:
0540: /**
0541: *
0542: */
0543: protected void exportRectangle(TableBuilder tableBuilder,
0544: JRPrintRectangle rectangle, JRExporterGridCell gridCell)
0545: throws IOException {
0546: tableBuilder.buildCellHeader(
0547: styleCache.getCellStyle(rectangle), gridCell
0548: .getColSpan(), gridCell.getRowSpan());
0549: tableBuilder.buildCellFooter();
0550: }
0551:
0552: /**
0553: *
0554: */
0555: protected void exportEllipse(TableBuilder tableBuilder,
0556: JRPrintEllipse ellipse, JRExporterGridCell gridCell)
0557: throws IOException {
0558: tableBuilder.buildCellHeader(null, gridCell.getColSpan(),
0559: gridCell.getRowSpan());
0560: tempBodyWriter.write("<text:p "
0561: //+ "text:style-name=\"Standard\""
0562: + ">" + "<draw:ellipse text:anchor-type=\"paragraph\" "
0563: + "draw:style-name=\""
0564: + styleCache.getGraphicStyle(ellipse) + "\" "
0565: + "svg:width=\""
0566: + Utility.translatePixelsToInches(ellipse.getWidth())
0567: + "in\" " + "svg:height=\""
0568: + Utility.translatePixelsToInches(ellipse.getHeight())
0569: + "in\" " + "svg:x=\"0in\" " + "svg:y=\"0in\">"
0570: + "<text:p/></draw:ellipse></text:p>");
0571: tableBuilder.buildCellFooter();
0572: }
0573:
0574: /**
0575: *
0576: */
0577: protected void exportText(TableBuilder tableBuilder,
0578: JRPrintText text, JRExporterGridCell gridCell)
0579: throws IOException {
0580: tableBuilder.buildCellHeader(styleCache.getCellStyle(text),
0581: gridCell.getColSpan(), gridCell.getRowSpan());
0582:
0583: JRStyledText styledText = getStyledText(text);
0584:
0585: int textLength = 0;
0586:
0587: if (styledText != null) {
0588: textLength = styledText.length();
0589: }
0590:
0591: // if (isWrapBreakWord)
0592: // {
0593: // styleBuffer.append("width: " + gridCell.width + "; ");
0594: // styleBuffer.append("word-wrap: break-word; ");
0595: // }
0596:
0597: // if (text.getLineSpacing() != JRTextElement.LINE_SPACING_SINGLE)
0598: // {
0599: // styleBuffer.append("line-height: " + text.getLineSpacingFactor() + "; ");
0600: // }
0601:
0602: // if (styleBuffer.length() > 0)
0603: // {
0604: // writer.write(" style=\"");
0605: // writer.write(styleBuffer.toString());
0606: // writer.write("\"");
0607: // }
0608: //
0609: // writer.write(">");
0610:
0611: // if (text.getAnchorName() != null)
0612: // {
0613: // writer.write("<a name=\"");
0614: // writer.write(text.getAnchorName());
0615: // writer.write("\"/>");
0616: // }
0617:
0618: // boolean startedHyperlink = startHyperlink(text);
0619:
0620: tempBodyWriter.write("<text:p");
0621: tempBodyWriter.write(" text:style-name=\""
0622: + styleCache.getParagraphStyle(text) + "\"");
0623: tempBodyWriter.write(">");
0624:
0625: if (textLength > 0) {
0626: exportStyledText(styledText);
0627: }
0628:
0629: // if (startedHyperlink)
0630: // {
0631: // endHyperlink();
0632: // }
0633:
0634: tempBodyWriter.write("</text:p>\n");
0635:
0636: tableBuilder.buildCellFooter();
0637: }
0638:
0639: /**
0640: *
0641: */
0642: protected void exportStyledText(JRStyledText styledText)
0643: throws IOException {
0644: String text = styledText.getText();
0645:
0646: int runLimit = 0;
0647:
0648: AttributedCharacterIterator iterator = styledText
0649: .getAttributedString().getIterator();
0650:
0651: while (runLimit < styledText.length()
0652: && (runLimit = iterator.getRunLimit()) <= styledText
0653: .length()) {
0654: exportStyledTextRun(iterator.getAttributes(), text
0655: .substring(iterator.getIndex(), runLimit));
0656:
0657: iterator.setIndex(runLimit);
0658: }
0659: }
0660:
0661: /**
0662: *
0663: */
0664: protected void exportStyledTextRun(Map attributes, String text)
0665: throws IOException {
0666: String textSpanStyleName = styleCache.getTextSpanStyle(
0667: attributes, text);
0668:
0669: tempBodyWriter.write("<text:span");
0670: tempBodyWriter.write(" text:style-name=\"" + textSpanStyleName
0671: + "\"");
0672: tempBodyWriter.write(">");
0673:
0674: if (text != null) {
0675: tempBodyWriter.write(Utility
0676: .replaceNewLineWithLineBreak(JRStringUtil
0677: .xmlEncode(text)));//FIXMEODT try something nicer for replace
0678: }
0679:
0680: tempBodyWriter.write("</text:span>");
0681: }
0682:
0683: /**
0684: *
0685: *
0686: protected boolean startHyperlink(JRPrintHyperlink link) throws IOException
0687: {
0688: String href = getHyperlinkURL(link);
0689:
0690: if (href != null)
0691: {
0692: writer.write("<a href=\"");
0693: writer.write(href);
0694: writer.write("\"");
0695:
0696: String target = getHyperlinkTarget(link);
0697: if (target != null)
0698: {
0699: writer.write(" target=\"");
0700: writer.write(target);
0701: writer.write("\"");
0702: }
0703:
0704: if (link.getHyperlinkTooltip() != null)
0705: {
0706: writer.write(" title=\"");
0707: writer.write(JRStringUtil.xmlEncode(link.getHyperlinkTooltip()));
0708: writer.write("\"");
0709: }
0710:
0711: writer.write(">");
0712: }
0713:
0714: return href != null;
0715: }
0716:
0717:
0718: protected String getHyperlinkTarget(JRPrintHyperlink link)
0719: {
0720: String target = null;
0721: switch(link.getHyperlinkTarget())
0722: {
0723: case JRHyperlink.HYPERLINK_TARGET_BLANK :
0724: {
0725: target = "_blank";
0726: break;
0727: }
0728: case JRHyperlink.HYPERLINK_TARGET_SELF :
0729: default :
0730: {
0731: break;
0732: }
0733: }
0734: return target;
0735: }
0736:
0737:
0738: protected String getHyperlinkURL(JRPrintHyperlink link)
0739: {
0740: String href = null;
0741: JRHyperlinkProducer customHandler = getCustomHandler(link);
0742: if (customHandler == null)
0743: {
0744: switch(link.getHyperlinkType())
0745: {
0746: case JRHyperlink.HYPERLINK_TYPE_REFERENCE :
0747: {
0748: if (link.getHyperlinkReference() != null)
0749: {
0750: href = link.getHyperlinkReference();
0751: }
0752: break;
0753: }
0754: case JRHyperlink.HYPERLINK_TYPE_LOCAL_ANCHOR :
0755: {
0756: if (link.getHyperlinkAnchor() != null)
0757: {
0758: href = "#" + link.getHyperlinkAnchor();
0759: }
0760: break;
0761: }
0762: case JRHyperlink.HYPERLINK_TYPE_LOCAL_PAGE :
0763: {
0764: if (link.getHyperlinkPage() != null)
0765: {
0766: href = "#" + JR_PAGE_ANCHOR_PREFIX + reportIndex + "_" + link.getHyperlinkPage().toString();
0767: }
0768: break;
0769: }
0770: case JRHyperlink.HYPERLINK_TYPE_REMOTE_ANCHOR :
0771: {
0772: if (
0773: link.getHyperlinkReference() != null &&
0774: link.getHyperlinkAnchor() != null
0775: )
0776: {
0777: href = link.getHyperlinkReference() + "#" + link.getHyperlinkAnchor();
0778: }
0779: break;
0780: }
0781: case JRHyperlink.HYPERLINK_TYPE_REMOTE_PAGE :
0782: {
0783: if (
0784: link.getHyperlinkReference() != null &&
0785: link.getHyperlinkPage() != null
0786: )
0787: {
0788: href = link.getHyperlinkReference() + "#" + JR_PAGE_ANCHOR_PREFIX + "0_" + link.getHyperlinkPage().toString();
0789: }
0790: break;
0791: }
0792: case JRHyperlink.HYPERLINK_TYPE_NONE :
0793: default :
0794: {
0795: break;
0796: }
0797: }
0798: }
0799: else
0800: {
0801: href = customHandler.getHyperlink(link);
0802: }
0803:
0804: return href;
0805: }
0806:
0807:
0808: protected JRHyperlinkProducer getCustomHandler(JRPrintHyperlink link)
0809: {
0810: return hyperlinkProducerFactory == null ? null : hyperlinkProducerFactory.getHandler(link.getLinkType());
0811: }
0812:
0813:
0814: protected void endHyperlink() throws IOException
0815: {
0816: writer.write("</a>");
0817: }
0818:
0819:
0820: /**
0821: *
0822: */
0823: protected void exportImage(TableBuilder tableBuilder,
0824: JRPrintImage image, JRExporterGridCell gridCell)
0825: throws JRException, IOException {
0826: int topPadding = image.getTopPadding();
0827: int leftPadding = image.getLeftPadding();
0828: int bottomPadding = image.getBottomPadding();
0829: int rightPadding = image.getRightPadding();
0830:
0831: int availableImageWidth = image.getWidth() - leftPadding
0832: - rightPadding;
0833: availableImageWidth = (availableImageWidth < 0) ? 0
0834: : availableImageWidth;
0835:
0836: int availableImageHeight = image.getHeight() - topPadding
0837: - bottomPadding;
0838: availableImageHeight = (availableImageHeight < 0) ? 0
0839: : availableImageHeight;
0840:
0841: int width = availableImageWidth;
0842: int height = availableImageHeight;
0843:
0844: int xoffset = 0;
0845: int yoffset = 0;
0846:
0847: tableBuilder.buildCellHeader(styleCache.getCellStyle(image),
0848: gridCell.getColSpan(), gridCell.getRowSpan());
0849:
0850: JRRenderable renderer = image.getRenderer();
0851:
0852: if (renderer != null && availableImageWidth > 0
0853: && availableImageHeight > 0) {
0854: if (renderer.getType() == JRRenderable.TYPE_IMAGE
0855: && !image.isLazy()) {
0856: // Non-lazy image renderers are all asked for their image data at some point.
0857: // Better to test and replace the renderer now, in case of lazy load error.
0858: renderer = JRImageRenderer
0859: .getOnErrorRendererForImageData(renderer, image
0860: .getOnErrorType());
0861: }
0862: } else {
0863: renderer = null;
0864: }
0865:
0866: if (renderer != null) {
0867: float xalignFactor = getXAlignFactor(image);
0868: float yalignFactor = getYAlignFactor(image);
0869:
0870: switch (image.getScaleImage()) {
0871: case JRImage.SCALE_IMAGE_FILL_FRAME: {
0872: width = availableImageWidth;
0873: height = availableImageHeight;
0874: xoffset = 0;
0875: yoffset = 0;
0876: break;
0877: }
0878: case JRImage.SCALE_IMAGE_CLIP:
0879: case JRImage.SCALE_IMAGE_RETAIN_SHAPE:
0880: default: {
0881: double normalWidth = availableImageWidth;
0882: double normalHeight = availableImageHeight;
0883:
0884: if (!image.isLazy()) {
0885: // Image load might fail.
0886: JRRenderable tmpRenderer = JRImageRenderer
0887: .getOnErrorRendererForDimension(renderer,
0888: image.getOnErrorType());
0889: Dimension2D dimension = tmpRenderer == null ? null
0890: : tmpRenderer.getDimension();
0891: // If renderer was replaced, ignore image dimension.
0892: if (tmpRenderer == renderer && dimension != null) {
0893: normalWidth = dimension.getWidth();
0894: normalHeight = dimension.getHeight();
0895: }
0896: }
0897:
0898: if (availableImageHeight > 0) {
0899: double ratio = (double) normalWidth
0900: / (double) normalHeight;
0901:
0902: if (ratio > availableImageWidth
0903: / (double) availableImageHeight) {
0904: width = availableImageWidth;
0905: height = (int) (width / ratio);
0906:
0907: } else {
0908: height = availableImageHeight;
0909: width = (int) (ratio * height);
0910: }
0911: }
0912:
0913: xoffset = (int) (xalignFactor * (availableImageWidth - width));
0914: yoffset = (int) (yalignFactor * (availableImageHeight - height));
0915: }
0916: }
0917:
0918: tempBodyWriter
0919: .write("<text:p "
0920: //+ "text:style-name=\"Standard\""
0921: + ">"
0922: + "<draw:frame text:anchor-type=\"paragraph\" "
0923: + "draw:style-name=\""
0924: + styleCache.getGraphicStyle(image)
0925: + "\" "
0926: + "svg:x=\""
0927: + Utility
0928: .translatePixelsToInches(leftPadding
0929: + xoffset)
0930: + "in\" "
0931: + "svg:y=\""
0932: + Utility
0933: .translatePixelsToInches(topPadding
0934: + yoffset) + "in\" "
0935: + "svg:width=\""
0936: + Utility.translatePixelsToInches(width)
0937: + "in\" " + "svg:height=\""
0938: + Utility.translatePixelsToInches(height)
0939: + "in\">");
0940: tempBodyWriter.write("<draw:image ");
0941: tempBodyWriter.write(" xlink:href=\""
0942: + getImagePath(renderer, image.isLazy(), gridCell)
0943: + "\"");
0944: tempBodyWriter.write(" xlink:type=\"simple\"");
0945: tempBodyWriter.write(" xlink:show=\"embed\"");
0946: tempBodyWriter.write(" xlink:actuate=\"onLoad\"");
0947: tempBodyWriter.write("/>\n");
0948: tempBodyWriter.write("</draw:frame></text:p>");
0949: }
0950:
0951: tableBuilder.buildCellFooter();
0952: }
0953:
0954: /**
0955: *
0956: */
0957: protected String getImagePath(JRRenderable renderer,
0958: boolean isLazy, JRExporterGridCell gridCell)
0959: throws IOException {
0960: String imagePath = null;
0961:
0962: if (renderer != null) {
0963: if (renderer.getType() == JRRenderable.TYPE_IMAGE
0964: && rendererToImagePathMap.containsKey(renderer
0965: .getId())) {
0966: imagePath = (String) rendererToImagePathMap
0967: .get(renderer.getId());
0968: } else {
0969: if (isLazy) {
0970: imagePath = ((JRImageRenderer) renderer)
0971: .getImageLocation();
0972: } else {
0973: JRPrintElementIndex imageIndex = getElementIndex(gridCell);
0974: imagesToProcess.add(imageIndex);
0975:
0976: String imageName = getImageName(imageIndex);
0977: imagePath = "Pictures/" + imageName;
0978: }
0979:
0980: rendererToImagePathMap.put(renderer.getId(), imagePath);
0981: }
0982: }
0983:
0984: return imagePath;
0985: }
0986:
0987: protected JRPrintElementIndex getElementIndex(
0988: JRExporterGridCell gridCell) {
0989: JRPrintElementIndex imageIndex = new JRPrintElementIndex(
0990: reportIndex, pageIndex, gridCell.getWrapper()
0991: .getAddress());
0992: return imageIndex;
0993: }
0994:
0995: /**
0996: *
0997: *
0998: protected void writeImageMap(String imageMapName, JRPrintHyperlink mainHyperlink, List imageMapAreas) throws IOException
0999: {
1000: writer.write("<map name=\"" + imageMapName + "\">\n");
1001:
1002: for (Iterator it = imageMapAreas.iterator(); it.hasNext();)
1003: {
1004: JRPrintImageAreaHyperlink areaHyperlink = (JRPrintImageAreaHyperlink) it.next();
1005: JRPrintImageArea area = areaHyperlink.getArea();
1006:
1007: writer.write(" <area shape=\"" + JRPrintImageArea.getHtmlShape(area.getShape()) + "\"");
1008: writeImageAreaCoordinates(area);
1009: writeImageAreaHyperlink(areaHyperlink.getHyperlink());
1010: writer.write("/>\n");
1011: }
1012:
1013: if (mainHyperlink.getHyperlinkType() != JRHyperlink.HYPERLINK_TYPE_NONE)
1014: {
1015: writer.write(" <area shape=\"default\"");
1016: writeImageAreaHyperlink(mainHyperlink);
1017: writer.write("/>\n");
1018: }
1019:
1020: writer.write("</map>\n");
1021: }
1022:
1023:
1024: protected void writeImageAreaCoordinates(JRPrintImageArea area) throws IOException
1025: {
1026: int[] coords = area.getCoordinates();
1027: if (coords != null && coords.length > 0)
1028: {
1029: StringBuffer coordsEnum = new StringBuffer(coords.length * 4);
1030: coordsEnum.append(coords[0]);
1031: for (int i = 1; i < coords.length; i++)
1032: {
1033: coordsEnum.append(',');
1034: coordsEnum.append(coords[i]);
1035: }
1036:
1037: writer.write(" coords=\"" + coordsEnum + "\"");
1038: }
1039: }
1040:
1041:
1042: protected void writeImageAreaHyperlink(JRPrintHyperlink hyperlink) throws IOException
1043: {
1044: String href = getHyperlinkURL(hyperlink);
1045: if (href == null)
1046: {
1047: writer.write(" nohref=\"nohref\"");
1048: }
1049: else
1050: {
1051: writer.write(" href=\"" + href + "\"");
1052:
1053: String target = getHyperlinkTarget(hyperlink);
1054: if (target != null)
1055: {
1056: writer.write(" target=\"");
1057: writer.write(target);
1058: writer.write("\"");
1059: }
1060: }
1061:
1062: if (hyperlink.getHyperlinkTooltip() != null)
1063: {
1064: writer.write(" title=\"");
1065: writer.write(JRStringUtil.xmlEncode(hyperlink.getHyperlinkTooltip()));
1066: writer.write("\"");
1067: }
1068: }
1069:
1070:
1071: /**
1072: *
1073: */
1074: public static String getImageName(
1075: JRPrintElementIndex printElementIndex) {
1076: return IMAGE_NAME_PREFIX + printElementIndex.toString();
1077: }
1078:
1079: /**
1080: *
1081: */
1082: public static JRPrintElementIndex getPrintElementIndex(
1083: String imageName) {
1084: if (!imageName.startsWith(IMAGE_NAME_PREFIX)) {
1085: throw new JRRuntimeException("Invalid image name: "
1086: + imageName);
1087: }
1088:
1089: return JRPrintElementIndex.parsePrintElementIndex(imageName
1090: .substring(IMAGE_NAME_PREFIX_LEGTH));
1091: }
1092:
1093: /**
1094: *
1095: */
1096: protected void exportFrame(TableBuilder tableBuilder,
1097: JRPrintFrame frame, JRExporterGridCell gridCell)
1098: throws IOException, JRException {
1099: tableBuilder.buildCellHeader(styleCache.getCellStyle(frame),
1100: gridCell.getColSpan(), gridCell.getRowSpan());
1101:
1102: boolean appendBackcolor = frame.getMode() == JRElement.MODE_OPAQUE
1103: && (backcolor == null || frame.getBackcolor().getRGB() != backcolor
1104: .getRGB());
1105:
1106: if (appendBackcolor) {
1107: setBackcolor(frame.getBackcolor());
1108: }
1109:
1110: try {
1111: JRGridLayout layout = gridCell.getLayout();
1112: JRPrintElementIndex frameIndex = new JRPrintElementIndex(
1113: reportIndex, pageIndex, gridCell.getWrapper()
1114: .getAddress());
1115: exportGrid(layout, frameIndex);
1116: } finally {
1117: if (appendBackcolor) {
1118: restoreBackcolor();
1119: }
1120: }
1121:
1122: tableBuilder.buildCellFooter();
1123: }
1124:
1125: /**
1126: *
1127: */
1128: protected void setBackcolor(Color color) {
1129: backcolorStack.addLast(backcolor);
1130:
1131: backcolor = color;
1132: }
1133:
1134: protected void restoreBackcolor() {
1135: backcolor = (Color) backcolorStack.removeLast();
1136: }
1137:
1138: private float getXAlignFactor(JRPrintImage image) {
1139: float xalignFactor = 0f;
1140: switch (image.getHorizontalAlignment()) {
1141: case JRAlignment.HORIZONTAL_ALIGN_RIGHT: {
1142: xalignFactor = 1f;
1143: break;
1144: }
1145: case JRAlignment.HORIZONTAL_ALIGN_CENTER: {
1146: xalignFactor = 0.5f;
1147: break;
1148: }
1149: case JRAlignment.HORIZONTAL_ALIGN_LEFT:
1150: default: {
1151: xalignFactor = 0f;
1152: break;
1153: }
1154: }
1155: return xalignFactor;
1156: }
1157:
1158: private float getYAlignFactor(JRPrintImage image) {
1159: float yalignFactor = 0f;
1160: switch (image.getVerticalAlignment()) {
1161: case JRAlignment.VERTICAL_ALIGN_BOTTOM: {
1162: yalignFactor = 1f;
1163: break;
1164: }
1165: case JRAlignment.VERTICAL_ALIGN_MIDDLE: {
1166: yalignFactor = 0.5f;
1167: break;
1168: }
1169: case JRAlignment.VERTICAL_ALIGN_TOP:
1170: default: {
1171: yalignFactor = 0f;
1172: break;
1173: }
1174: }
1175: return yalignFactor;
1176: }
1177:
1178: }
|