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: * Contributors:
0031: * Alex Parfenov - aparfeno@users.sourceforge.net
0032: * Adrian Jackson - iapetus@users.sourceforge.net
0033: * David Taylor - exodussystems@users.sourceforge.net
0034: * Lars Kristensen - llk@users.sourceforge.net
0035: */
0036:
0037: package net.sf.jasperreports.engine.export;
0038:
0039: import java.awt.Color;
0040: import java.awt.Dimension;
0041: import java.awt.Rectangle;
0042: import java.awt.font.TextAttribute;
0043: import java.awt.geom.Dimension2D;
0044: import java.io.File;
0045: import java.io.FileOutputStream;
0046: import java.io.IOException;
0047: import java.io.OutputStream;
0048: import java.io.OutputStreamWriter;
0049: import java.io.StringWriter;
0050: import java.io.Writer;
0051: import java.text.AttributedCharacterIterator;
0052: import java.util.ArrayList;
0053: import java.util.HashMap;
0054: import java.util.Iterator;
0055: import java.util.LinkedList;
0056: import java.util.List;
0057: import java.util.Map;
0058:
0059: import net.sf.jasperreports.engine.JRAbstractExporter;
0060: import net.sf.jasperreports.engine.JRAlignment;
0061: import net.sf.jasperreports.engine.JRBox;
0062: import net.sf.jasperreports.engine.JRElement;
0063: import net.sf.jasperreports.engine.JRException;
0064: import net.sf.jasperreports.engine.JRExporterParameter;
0065: import net.sf.jasperreports.engine.JRGraphicElement;
0066: import net.sf.jasperreports.engine.JRHyperlink;
0067: import net.sf.jasperreports.engine.JRImage;
0068: import net.sf.jasperreports.engine.JRImageMapRenderer;
0069: import net.sf.jasperreports.engine.JRImageRenderer;
0070: import net.sf.jasperreports.engine.JRPrintElement;
0071: import net.sf.jasperreports.engine.JRPrintElementIndex;
0072: import net.sf.jasperreports.engine.JRPrintEllipse;
0073: import net.sf.jasperreports.engine.JRPrintFrame;
0074: import net.sf.jasperreports.engine.JRPrintHyperlink;
0075: import net.sf.jasperreports.engine.JRPrintImage;
0076: import net.sf.jasperreports.engine.JRPrintImageArea;
0077: import net.sf.jasperreports.engine.JRPrintImageAreaHyperlink;
0078: import net.sf.jasperreports.engine.JRPrintLine;
0079: import net.sf.jasperreports.engine.JRPrintPage;
0080: import net.sf.jasperreports.engine.JRPrintRectangle;
0081: import net.sf.jasperreports.engine.JRPrintText;
0082: import net.sf.jasperreports.engine.JRRenderable;
0083: import net.sf.jasperreports.engine.JRRuntimeException;
0084: import net.sf.jasperreports.engine.JRTextElement;
0085: import net.sf.jasperreports.engine.JRWrappingSvgRenderer;
0086: import net.sf.jasperreports.engine.JasperPrint;
0087: import net.sf.jasperreports.engine.util.JRColorUtil;
0088: import net.sf.jasperreports.engine.util.JRProperties;
0089: import net.sf.jasperreports.engine.util.JRStringUtil;
0090: import net.sf.jasperreports.engine.util.JRStyledText;
0091: import net.sf.jasperreports.engine.util.Pair;
0092:
0093: /**
0094: * Exports a JasperReports document to HTML format. It has character output type and exports the document to a
0095: * grid-based layout.
0096: * <p>
0097: * Since classic AWT fonts can be sometimes very different from HTML fonts, a font mapping feature was added.
0098: * By using the {@link JRExporterParameter#FONT_MAP} parameter, a logical font like "sansserif" can be mapped to a
0099: * list of HTML specific fonts, like "Arial, Verdana, Tahoma". Both map keys and values are strings.
0100: * @author Teodor Danciu (teodord@users.sourceforge.net)
0101: * @version $Id: JRHtmlExporter.java 1824 2007-08-23 14:19:12Z teodord $
0102: */
0103: public class JRHtmlExporter extends JRAbstractExporter {
0104:
0105: /**
0106: * @deprecated Replaced by {@link JRHtmlExporterParameter#PROPERTY_FRAMES_AS_NESTED_TABLES}.
0107: */
0108: public static final String PROPERTY_FRAMES_AS_NESTED_TABLES = JRHtmlExporterParameter.PROPERTY_FRAMES_AS_NESTED_TABLES;
0109:
0110: /**
0111: *
0112: */
0113: protected static final String JR_PAGE_ANCHOR_PREFIX = "JR_PAGE_ANCHOR_";
0114:
0115: /**
0116: *
0117: */
0118: protected static final String CSS_TEXT_ALIGN_LEFT = "left";
0119: protected static final String CSS_TEXT_ALIGN_RIGHT = "right";
0120: protected static final String CSS_TEXT_ALIGN_CENTER = "center";
0121: protected static final String CSS_TEXT_ALIGN_JUSTIFY = "justify";
0122:
0123: /**
0124: *
0125: */
0126: protected static final String HTML_VERTICAL_ALIGN_TOP = "top";
0127: protected static final String HTML_VERTICAL_ALIGN_MIDDLE = "middle";
0128: protected static final String HTML_VERTICAL_ALIGN_BOTTOM = "bottom";
0129:
0130: public static final String IMAGE_NAME_PREFIX = "img_";
0131: protected static final int IMAGE_NAME_PREFIX_LEGTH = IMAGE_NAME_PREFIX
0132: .length();
0133:
0134: /**
0135: *
0136: */
0137: protected Writer writer = null;
0138: protected JRExportProgressMonitor progressMonitor = null;
0139: protected Map rendererToImagePathMap = null;
0140: protected Map imageMaps;
0141: protected Map imageNameToImageDataMap = null;
0142: protected List imagesToProcess = null;
0143: protected boolean isPxImageLoaded = false;
0144:
0145: protected int reportIndex = 0;
0146: protected int pageIndex = 0;
0147:
0148: /**
0149: *
0150: */
0151: protected File imagesDir = null;
0152: protected String imagesURI = null;
0153: protected boolean isOutputImagesToDir = false;
0154: protected boolean isRemoveEmptySpace;
0155: protected boolean isWhitePageBackground;
0156: protected String encoding;
0157: protected String sizeUnit = null;
0158: protected boolean isUsingImagesToAlign;
0159: protected boolean isWrapBreakWord;
0160:
0161: /**
0162: *
0163: */
0164: protected String htmlHeader = null;
0165: protected String betweenPagesHtml = null;
0166: protected String htmlFooter = null;
0167:
0168: protected StringProvider emptyCellStringProvider = null;
0169:
0170: /**
0171: *
0172: */
0173: protected Map fontMap = null;
0174:
0175: private LinkedList backcolorStack;
0176: private Color backcolor;
0177:
0178: protected JRHyperlinkProducerFactory hyperlinkProducerFactory;
0179:
0180: protected boolean deepGrid;
0181:
0182: public JRHtmlExporter() {
0183: backcolorStack = new LinkedList();
0184: backcolor = null;
0185: }
0186:
0187: /**
0188: *
0189: */
0190: public void exportReport() throws JRException {
0191: progressMonitor = (JRExportProgressMonitor) parameters
0192: .get(JRExporterParameter.PROGRESS_MONITOR);
0193:
0194: /* */
0195: setOffset();
0196:
0197: try {
0198: /* */
0199: setExportContext();
0200:
0201: /* */
0202: setInput();
0203:
0204: /* */
0205: if (!isModeBatch) {
0206: setPageRange();
0207: }
0208:
0209: htmlHeader = (String) parameters
0210: .get(JRHtmlExporterParameter.HTML_HEADER);
0211: betweenPagesHtml = (String) parameters
0212: .get(JRHtmlExporterParameter.BETWEEN_PAGES_HTML);
0213: htmlFooter = (String) parameters
0214: .get(JRHtmlExporterParameter.HTML_FOOTER);
0215:
0216: imagesDir = (File) parameters
0217: .get(JRHtmlExporterParameter.IMAGES_DIR);
0218: if (imagesDir == null) {
0219: String dir = (String) parameters
0220: .get(JRHtmlExporterParameter.IMAGES_DIR_NAME);
0221: if (dir != null) {
0222: imagesDir = new File(dir);
0223: }
0224: }
0225:
0226: isRemoveEmptySpace = getBooleanParameter(
0227: JRHtmlExporterParameter.IS_REMOVE_EMPTY_SPACE_BETWEEN_ROWS,
0228: JRHtmlExporterParameter.PROPERTY_REMOVE_EMPTY_SPACE_BETWEEN_ROWS,
0229: false);
0230:
0231: isWhitePageBackground = getBooleanParameter(
0232: JRHtmlExporterParameter.IS_WHITE_PAGE_BACKGROUND,
0233: JRHtmlExporterParameter.PROPERTY_WHITE_PAGE_BACKGROUND,
0234: true);
0235:
0236: Boolean isOutputImagesToDirParameter = (Boolean) parameters
0237: .get(JRHtmlExporterParameter.IS_OUTPUT_IMAGES_TO_DIR);
0238: if (isOutputImagesToDirParameter != null) {
0239: isOutputImagesToDir = isOutputImagesToDirParameter
0240: .booleanValue();
0241: }
0242:
0243: String uri = (String) parameters
0244: .get(JRHtmlExporterParameter.IMAGES_URI);
0245: if (uri != null) {
0246: imagesURI = uri;
0247: }
0248:
0249: encoding = getStringParameterOrDefault(
0250: JRExporterParameter.CHARACTER_ENCODING,
0251: JRExporterParameter.PROPERTY_CHARACTER_ENCODING);
0252:
0253: rendererToImagePathMap = new HashMap();
0254: imageMaps = new HashMap();
0255: imagesToProcess = new ArrayList();
0256: isPxImageLoaded = false;
0257:
0258: //backward compatibility with the IMAGE_MAP parameter
0259: imageNameToImageDataMap = (Map) parameters
0260: .get(JRHtmlExporterParameter.IMAGES_MAP);
0261: // if (imageNameToImageDataMap == null)
0262: // {
0263: // imageNameToImageDataMap = new HashMap();
0264: // }
0265: //END - backward compatibility with the IMAGE_MAP parameter
0266:
0267: isWrapBreakWord = getBooleanParameter(
0268: JRHtmlExporterParameter.IS_WRAP_BREAK_WORD,
0269: JRHtmlExporterParameter.PROPERTY_WRAP_BREAK_WORD,
0270: false);
0271:
0272: sizeUnit = getStringParameterOrDefault(
0273: JRHtmlExporterParameter.SIZE_UNIT,
0274: JRHtmlExporterParameter.PROPERTY_SIZE_UNIT);
0275:
0276: isUsingImagesToAlign = getBooleanParameter(
0277: JRHtmlExporterParameter.IS_USING_IMAGES_TO_ALIGN,
0278: JRHtmlExporterParameter.PROPERTY_USING_IMAGES_TO_ALIGN,
0279: true);
0280:
0281: if (isUsingImagesToAlign) {
0282: emptyCellStringProvider = new StringProvider() {
0283: public String getStringForCollapsedTD(Object value,
0284: int width, int height, String sizeUnit) {
0285: return "><img alt=\"\" src=\"" + value
0286: + "px\" style=\"width: " + width
0287: + sizeUnit + "; height: " + height
0288: + sizeUnit + ";\"/>";
0289: }
0290:
0291: public String getStringForEmptyTD(Object value) {
0292: return "<img alt=\"\" src=\"" + value
0293: + "px\" border=\"0\"/>";
0294: }
0295: };
0296:
0297: loadPxImage();
0298: } else {
0299: emptyCellStringProvider = new StringProvider() {
0300: public String getStringForCollapsedTD(Object value,
0301: int width, int height, String sizeUnit) {
0302: return " style=\"width: " + width + sizeUnit
0303: + "; height: " + height + sizeUnit
0304: + ";\">";
0305: }
0306:
0307: public String getStringForEmptyTD(Object value) {
0308: return "";
0309: }
0310: };
0311: }
0312:
0313: fontMap = (Map) parameters
0314: .get(JRExporterParameter.FONT_MAP);
0315:
0316: setHyperlinkProducerFactory();
0317: setDeepGrid();
0318:
0319: StringBuffer sb = (StringBuffer) parameters
0320: .get(JRExporterParameter.OUTPUT_STRING_BUFFER);
0321: if (sb != null) {
0322: try {
0323: writer = new StringWriter();
0324: exportReportToWriter();
0325: sb.append(writer.toString());
0326: } catch (IOException e) {
0327: throw new JRException(
0328: "Error writing to StringBuffer writer : "
0329: + jasperPrint.getName(), e);
0330: } finally {
0331: if (writer != null) {
0332: try {
0333: writer.close();
0334: } catch (IOException e) {
0335: }
0336: }
0337: }
0338: } else {
0339: writer = (Writer) parameters
0340: .get(JRExporterParameter.OUTPUT_WRITER);
0341: if (writer != null) {
0342: try {
0343: exportReportToWriter();
0344: } catch (IOException e) {
0345: throw new JRException(
0346: "Error writing to writer : "
0347: + jasperPrint.getName(), e);
0348: }
0349: } else {
0350: OutputStream os = (OutputStream) parameters
0351: .get(JRExporterParameter.OUTPUT_STREAM);
0352: if (os != null) {
0353: try {
0354: writer = new OutputStreamWriter(os,
0355: encoding);
0356: exportReportToWriter();
0357: } catch (IOException e) {
0358: throw new JRException(
0359: "Error writing to OutputStream writer : "
0360: + jasperPrint.getName(), e);
0361: }
0362: } else {
0363: File destFile = (File) parameters
0364: .get(JRExporterParameter.OUTPUT_FILE);
0365: if (destFile == null) {
0366: String fileName = (String) parameters
0367: .get(JRExporterParameter.OUTPUT_FILE_NAME);
0368: if (fileName != null) {
0369: destFile = new File(fileName);
0370: } else {
0371: throw new JRException(
0372: "No output specified for the exporter.");
0373: }
0374: }
0375:
0376: try {
0377: os = new FileOutputStream(destFile);
0378: writer = new OutputStreamWriter(os,
0379: encoding);
0380: } catch (IOException e) {
0381: throw new JRException(
0382: "Error creating to file writer : "
0383: + jasperPrint.getName(), e);
0384: }
0385:
0386: if (imagesDir == null) {
0387: imagesDir = new File(destFile.getParent(),
0388: destFile.getName() + "_files");
0389: }
0390:
0391: if (isOutputImagesToDirParameter == null) {
0392: isOutputImagesToDir = true;
0393: }
0394:
0395: if (imagesURI == null) {
0396: imagesURI = imagesDir.getName() + "/";
0397: }
0398:
0399: try {
0400: exportReportToWriter();
0401: } catch (IOException e) {
0402: throw new JRException(
0403: "Error writing to file writer : "
0404: + jasperPrint.getName(), e);
0405: } finally {
0406: if (writer != null) {
0407: try {
0408: writer.close();
0409: } catch (IOException e) {
0410: }
0411: }
0412: }
0413: }
0414: }
0415: }
0416:
0417: if (isOutputImagesToDir) {
0418: if (imagesDir == null) {
0419: throw new JRException(
0420: "The images directory was not specified for the exporter.");
0421: }
0422:
0423: if (isPxImageLoaded
0424: || (imagesToProcess != null && imagesToProcess
0425: .size() > 0)) {
0426: if (!imagesDir.exists()) {
0427: imagesDir.mkdir();
0428: }
0429:
0430: if (isPxImageLoaded) {
0431: JRRenderable pxRenderer = JRImageRenderer
0432: .getInstance("net/sf/jasperreports/engine/images/pixel.GIF");
0433: byte[] imageData = pxRenderer.getImageData();
0434:
0435: File imageFile = new File(imagesDir, "px");
0436: FileOutputStream fos = null;
0437:
0438: try {
0439: fos = new FileOutputStream(imageFile);
0440: fos.write(imageData, 0, imageData.length);
0441: } catch (IOException e) {
0442: throw new JRException(
0443: "Error writing to image file : "
0444: + imageFile, e);
0445: } finally {
0446: if (fos != null) {
0447: try {
0448: fos.close();
0449: } catch (IOException e) {
0450: }
0451: }
0452: }
0453: }
0454:
0455: for (Iterator it = imagesToProcess.iterator(); it
0456: .hasNext();) {
0457: JRPrintElementIndex imageIndex = (JRPrintElementIndex) it
0458: .next();
0459:
0460: JRPrintImage image = getImage(jasperPrintList,
0461: imageIndex);
0462: JRRenderable renderer = image.getRenderer();
0463: if (renderer.getType() == JRRenderable.TYPE_SVG) {
0464: renderer = new JRWrappingSvgRenderer(
0465: renderer, new Dimension(image
0466: .getWidth(), image
0467: .getHeight()),
0468: JRElement.MODE_OPAQUE == image
0469: .getMode() ? image
0470: .getBackcolor() : null);
0471: }
0472:
0473: byte[] imageData = renderer.getImageData();
0474:
0475: File imageFile = new File(imagesDir,
0476: getImageName(imageIndex));
0477: FileOutputStream fos = null;
0478:
0479: try {
0480: fos = new FileOutputStream(imageFile);
0481: fos.write(imageData, 0, imageData.length);
0482: } catch (IOException e) {
0483: throw new JRException(
0484: "Error writing to image file : "
0485: + imageFile, e);
0486: } finally {
0487: if (fos != null) {
0488: try {
0489: fos.close();
0490: } catch (IOException e) {
0491: }
0492: }
0493: }
0494: }
0495: }
0496: }
0497: } finally {
0498: resetExportContext();
0499: }
0500: }
0501:
0502: protected void setHyperlinkProducerFactory() {
0503: hyperlinkProducerFactory = (JRHyperlinkProducerFactory) parameters
0504: .get(JRExporterParameter.HYPERLINK_PRODUCER_FACTORY);
0505: }
0506:
0507: protected void setDeepGrid() {
0508: boolean nestedTables;
0509: Boolean nestedTablesParam = (Boolean) parameters
0510: .get(JRHtmlExporterParameter.FRAMES_AS_NESTED_TABLES);
0511: if (nestedTablesParam == null) {
0512: nestedTables = JRProperties
0513: .getBooleanProperty(PROPERTY_FRAMES_AS_NESTED_TABLES);
0514: } else {
0515: nestedTables = nestedTablesParam.booleanValue();
0516: }
0517:
0518: deepGrid = !nestedTables;
0519: }
0520:
0521: public static JRPrintImage getImage(List jasperPrintList,
0522: String imageName) {
0523: return getImage(jasperPrintList,
0524: getPrintElementIndex(imageName));
0525: }
0526:
0527: public static JRPrintImage getImage(List jasperPrintList,
0528: JRPrintElementIndex imageIndex) {
0529: JasperPrint report = (JasperPrint) jasperPrintList
0530: .get(imageIndex.getReportIndex());
0531: JRPrintPage page = (JRPrintPage) report.getPages().get(
0532: imageIndex.getPageIndex());
0533:
0534: Integer[] elementIndexes = imageIndex.getAddressArray();
0535: Object element = page.getElements().get(
0536: elementIndexes[0].intValue());
0537:
0538: for (int i = 1; i < elementIndexes.length; ++i) {
0539: JRPrintFrame frame = (JRPrintFrame) element;
0540: element = frame.getElements().get(
0541: elementIndexes[i].intValue());
0542: }
0543:
0544: return (JRPrintImage) element;
0545: }
0546:
0547: /**
0548: *
0549: */
0550: protected void exportReportToWriter() throws JRException,
0551: IOException {
0552: if (htmlHeader == null) {
0553: // no doctype because of bug 1430880
0554: // writer.write("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n");
0555: // writer.write("<html xmlns=\"http://www.w3.org/1999/xhtml\">\n");
0556: writer.write("<html>\n");
0557: writer.write("<head>\n");
0558: writer.write(" <title></title>\n");
0559: writer
0560: .write(" <meta http-equiv=\"Content-Type\" content=\"text/html; charset="
0561: + encoding + "\"/>\n");
0562: writer.write(" <style type=\"text/css\">\n");
0563: writer.write(" a {text-decoration: none}\n");
0564: writer.write(" </style>\n");
0565: writer.write("</head>\n");
0566: writer
0567: .write("<body text=\"#000000\" link=\"#000000\" alink=\"#000000\" vlink=\"#000000\">\n");
0568: writer
0569: .write("<table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\">\n");
0570: writer
0571: .write("<tr><td width=\"50%\"> </td><td align=\"center\">\n");
0572: writer.write("\n");
0573: } else {
0574: writer.write(htmlHeader);
0575: }
0576:
0577: for (reportIndex = 0; reportIndex < jasperPrintList.size(); reportIndex++) {
0578: jasperPrint = (JasperPrint) jasperPrintList
0579: .get(reportIndex);
0580:
0581: List pages = jasperPrint.getPages();
0582: if (pages != null && pages.size() > 0) {
0583: if (isModeBatch) {
0584: startPageIndex = 0;
0585: endPageIndex = pages.size() - 1;
0586: }
0587:
0588: JRPrintPage page = null;
0589: for (pageIndex = startPageIndex; pageIndex <= endPageIndex; pageIndex++) {
0590: if (Thread.currentThread().isInterrupted()) {
0591: throw new JRException(
0592: "Current thread interrupted.");
0593: }
0594:
0595: page = (JRPrintPage) pages.get(pageIndex);
0596:
0597: writer.write("<a name=\"" + JR_PAGE_ANCHOR_PREFIX
0598: + reportIndex + "_" + (pageIndex + 1)
0599: + "\"/>\n");
0600:
0601: /* */
0602: exportPage(page);
0603:
0604: if (reportIndex < jasperPrintList.size() - 1
0605: || pageIndex < endPageIndex) {
0606: if (betweenPagesHtml == null) {
0607: writer.write("<br/>\n<br/>\n");
0608: } else {
0609: writer.write(betweenPagesHtml);
0610: }
0611: }
0612:
0613: writer.write("\n");
0614: }
0615: }
0616: }
0617:
0618: if (htmlFooter == null) {
0619: writer.write("</td><td width=\"50%\"> </td></tr>\n");
0620: writer.write("</table>\n");
0621: writer.write("</body>\n");
0622: writer.write("</html>\n");
0623: } else {
0624: writer.write(htmlFooter);
0625: }
0626:
0627: writer.flush();
0628: }
0629:
0630: /**
0631: *
0632: */
0633: protected void exportPage(JRPrintPage page) throws JRException,
0634: IOException {
0635: JRGridLayout layout = new JRGridLayout(JRHtmlExporterNature
0636: .getInstance(deepGrid), page.getElements(), jasperPrint
0637: .getPageWidth(), jasperPrint.getPageHeight(),
0638: globalOffsetX, globalOffsetY, null //address
0639: );
0640:
0641: exportGrid(layout, isWhitePageBackground);
0642:
0643: if (progressMonitor != null) {
0644: progressMonitor.afterPageExport();
0645: }
0646: }
0647:
0648: /**
0649: *
0650: */
0651: protected void exportGrid(JRGridLayout gridLayout,
0652: boolean whitePageBackground) throws IOException,
0653: JRException {
0654: List xCuts = gridLayout.getXCuts();
0655: JRExporterGridCell[][] grid = gridLayout.getGrid();
0656:
0657: writer
0658: .write("<table style=\"width: "
0659: + gridLayout.getWidth()
0660: + sizeUnit
0661: + "\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\"");
0662: if (whitePageBackground) {
0663: writer.write(" bgcolor=\"white\"");
0664: }
0665: writer.write(">\n");
0666:
0667: if (whitePageBackground) {
0668: setBackcolor(Color.white);
0669: }
0670:
0671: writer.write("<tr>\n");
0672: int width = 0;
0673: for (int i = 1; i < xCuts.size(); i++) {
0674: width = ((Integer) xCuts.get(i)).intValue()
0675: - ((Integer) xCuts.get(i - 1)).intValue();
0676: writer.write(" <td"
0677: + emptyCellStringProvider.getStringForCollapsedTD(
0678: imagesURI, width, 1, sizeUnit) + "</td>\n");
0679: }
0680: writer.write("</tr>\n");
0681:
0682: for (int y = 0; y < grid.length; y++) {
0683: if (gridLayout.isRowSpanned(y) || !isRemoveEmptySpace) {
0684: JRExporterGridCell[] gridRow = grid[y];
0685:
0686: int rowHeight = JRGridLayout.getRowHeight(gridRow);
0687:
0688: boolean hasEmptyCell = hasEmptyCell(gridRow);
0689:
0690: writer.write("<tr valign=\"top\"");
0691: if (!hasEmptyCell) {
0692: writer.write(" style=\"height:" + rowHeight
0693: + sizeUnit + "\"");
0694: }
0695: writer.write(">\n");
0696:
0697: for (int x = 0; x < gridRow.length; x++) {
0698: JRExporterGridCell gridCell = gridRow[x];
0699: if (gridCell.getWrapper() == null) {
0700: writeEmptyCell(gridCell, rowHeight);
0701: } else {
0702: JRPrintElement element = gridCell.getWrapper()
0703: .getElement();
0704:
0705: if (element instanceof JRPrintLine) {
0706: exportLine((JRPrintLine) element, gridCell);
0707: } else if (element instanceof JRPrintRectangle) {
0708: exportRectangle(element, gridCell);
0709: } else if (element instanceof JRPrintEllipse) {
0710: exportRectangle(element, gridCell);
0711: } else if (element instanceof JRPrintImage) {
0712: exportImage((JRPrintImage) element,
0713: gridCell);
0714: } else if (element instanceof JRPrintText) {
0715: exportText((JRPrintText) element, gridCell);
0716: } else if (element instanceof JRPrintFrame) {
0717: exportFrame((JRPrintFrame) element,
0718: gridCell);
0719: }
0720: }
0721:
0722: x += gridCell.getColSpan() - 1;
0723: }
0724:
0725: writer.write("</tr>\n");
0726: }
0727: }
0728:
0729: if (whitePageBackground) {
0730: restoreBackcolor();
0731: }
0732:
0733: writer.write("</table>\n");
0734: }
0735:
0736: private boolean hasEmptyCell(JRExporterGridCell[] gridRow) {
0737: if (gridRow[0].getWrapper() == null) // quick exit
0738: {
0739: return true;
0740: }
0741:
0742: boolean hasEmptyCell = false;
0743: for (int x = 1; x < gridRow.length; x++) {
0744: if (gridRow[x].getWrapper() == null) {
0745: hasEmptyCell = true;
0746: break;
0747: }
0748: }
0749:
0750: return hasEmptyCell;
0751: }
0752:
0753: protected void writeEmptyCell(JRExporterGridCell cell, int rowHeight)
0754: throws IOException {
0755: writer.write(" <td");
0756: if (cell.getColSpan() > 1) {
0757: writer.write(" colspan=\"" + cell.getColSpan() + "\"");
0758: }
0759:
0760: StringBuffer styleBuffer = new StringBuffer();
0761: appendBackcolorStyle(cell, styleBuffer);
0762: appendBorderStyle(cell.getBox(), styleBuffer);
0763:
0764: if (styleBuffer.length() > 0) {
0765: writer.write(" style=\"");
0766: writer.write(styleBuffer.toString());
0767: writer.write("\"");
0768: }
0769:
0770: writer.write(emptyCellStringProvider.getStringForCollapsedTD(
0771: imagesURI, cell.getWidth(), rowHeight, sizeUnit));
0772: writer.write("</td>\n");
0773: }
0774:
0775: /**
0776: *
0777: */
0778: protected void exportLine(JRPrintLine line,
0779: JRExporterGridCell gridCell) throws IOException {
0780: writeCellTDStart(gridCell);
0781:
0782: if (line.getForecolor().getRGB() != Color.white.getRGB()) {
0783: writer.write(" bgcolor=\"#");
0784: writer.write(JRColorUtil.getColorHexa(line.getForecolor()));
0785: writer.write("\"");
0786: }
0787:
0788: writer.write(">");
0789:
0790: writer.write(emptyCellStringProvider
0791: .getStringForEmptyTD(imagesURI));
0792:
0793: writer.write("</td>\n");
0794: }
0795:
0796: /**
0797: *
0798: */
0799: protected void writeCellTDStart(JRExporterGridCell gridCell)
0800: throws IOException {
0801: writer.write(" <td");
0802: if (gridCell.getColSpan() > 1) {
0803: writer.write(" colspan=\"" + gridCell.getColSpan() + "\"");
0804: }
0805: if (gridCell.getRowSpan() > 1) {
0806: writer.write(" rowspan=\"" + gridCell.getRowSpan() + "\"");
0807: }
0808: }
0809:
0810: /**
0811: *
0812: */
0813: protected void exportRectangle(JRPrintElement element,
0814: JRExporterGridCell gridCell) throws IOException {
0815: writeCellTDStart(gridCell);
0816:
0817: if ((backcolor == null || element.getBackcolor().getRGB() != backcolor
0818: .getRGB())
0819: && element.getMode() == JRElement.MODE_OPAQUE) {
0820: writer.write(" bgcolor=\"#");
0821: writer.write(JRColorUtil.getColorHexa(element
0822: .getBackcolor()));
0823: writer.write("\"");
0824: }
0825:
0826: writer.write(">");
0827:
0828: writer.write(emptyCellStringProvider
0829: .getStringForEmptyTD(imagesURI));
0830:
0831: writer.write("</td>\n");
0832: }
0833:
0834: /**
0835: *
0836: */
0837: protected void exportStyledText(JRStyledText styledText)
0838: throws IOException {
0839: String text = styledText.getText();
0840:
0841: int runLimit = 0;
0842:
0843: AttributedCharacterIterator iterator = styledText
0844: .getAttributedString().getIterator();
0845:
0846: while (runLimit < styledText.length()
0847: && (runLimit = iterator.getRunLimit()) <= styledText
0848: .length()) {
0849: exportStyledTextRun(iterator.getAttributes(), text
0850: .substring(iterator.getIndex(), runLimit));
0851:
0852: iterator.setIndex(runLimit);
0853: }
0854: }
0855:
0856: /**
0857: *
0858: */
0859: protected void exportStyledTextRun(Map attributes, String text)
0860: throws IOException {
0861: String fontFamily;
0862: String fontFamilyAttr = (String) attributes
0863: .get(TextAttribute.FAMILY);
0864: if (fontMap != null && fontMap.containsKey(fontFamilyAttr)) {
0865: fontFamily = (String) fontMap.get(fontFamilyAttr);
0866: } else {
0867: fontFamily = fontFamilyAttr;
0868: }
0869: writer.write("<span style=\"font-family: ");
0870: writer.write(fontFamily);
0871: writer.write("; ");
0872:
0873: Color forecolor = (Color) attributes
0874: .get(TextAttribute.FOREGROUND);
0875: if (!Color.black.equals(forecolor)) {
0876: writer.write("color: #");
0877: writer.write(JRColorUtil.getColorHexa(forecolor));
0878: writer.write("; ");
0879: }
0880:
0881: Color runBackcolor = (Color) attributes
0882: .get(TextAttribute.BACKGROUND);
0883: if (runBackcolor != null) {
0884: writer.write("background-color: #");
0885: writer.write(JRColorUtil.getColorHexa(runBackcolor));
0886: writer.write("; ");
0887: }
0888:
0889: writer.write("font-size: ");
0890: writer
0891: .write(String.valueOf(attributes
0892: .get(TextAttribute.SIZE)));
0893: writer.write(sizeUnit);
0894: writer.write(";");
0895:
0896: /*
0897: if (!horizontalAlignment.equals(CSS_TEXT_ALIGN_LEFT))
0898: {
0899: writer.write(" text-align: ");
0900: writer.write(horizontalAlignment);
0901: writer.write(";");
0902: }
0903: */
0904:
0905: if (TextAttribute.WEIGHT_BOLD.equals(attributes
0906: .get(TextAttribute.WEIGHT))) {
0907: writer.write(" font-weight: bold;");
0908: }
0909: if (TextAttribute.POSTURE_OBLIQUE.equals(attributes
0910: .get(TextAttribute.POSTURE))) {
0911: writer.write(" font-style: italic;");
0912: }
0913: if (TextAttribute.UNDERLINE_ON.equals(attributes
0914: .get(TextAttribute.UNDERLINE))) {
0915: writer.write(" text-decoration: underline;");
0916: }
0917: if (TextAttribute.STRIKETHROUGH_ON.equals(attributes
0918: .get(TextAttribute.STRIKETHROUGH))) {
0919: writer.write(" text-decoration: line-through;");
0920: }
0921:
0922: if (TextAttribute.SUPERSCRIPT_SUPER.equals(attributes
0923: .get(TextAttribute.SUPERSCRIPT))) {
0924: writer.write(" vertical-align: super;");
0925: } else if (TextAttribute.SUPERSCRIPT_SUB.equals(attributes
0926: .get(TextAttribute.SUPERSCRIPT))) {
0927: writer.write(" vertical-align: sub;");
0928: }
0929:
0930: writer.write("\">");
0931:
0932: writer.write(JRStringUtil.htmlEncode(text));
0933:
0934: writer.write("</span>");
0935: }
0936:
0937: /**
0938: *
0939: */
0940: protected void exportText(JRPrintText text,
0941: JRExporterGridCell gridCell) throws IOException {
0942: JRStyledText styledText = getStyledText(text);
0943:
0944: int textLength = 0;
0945:
0946: if (styledText != null) {
0947: textLength = styledText.length();
0948: }
0949:
0950: writeCellTDStart(gridCell);//FIXME why dealing with cell style if no text to print (textLength == 0)?
0951:
0952: String verticalAlignment = HTML_VERTICAL_ALIGN_TOP;
0953:
0954: switch (text.getVerticalAlignment()) {
0955: case JRAlignment.VERTICAL_ALIGN_BOTTOM: {
0956: verticalAlignment = HTML_VERTICAL_ALIGN_BOTTOM;
0957: break;
0958: }
0959: case JRAlignment.VERTICAL_ALIGN_MIDDLE: {
0960: verticalAlignment = HTML_VERTICAL_ALIGN_MIDDLE;
0961: break;
0962: }
0963: case JRAlignment.VERTICAL_ALIGN_TOP:
0964: default: {
0965: verticalAlignment = HTML_VERTICAL_ALIGN_TOP;
0966: }
0967: }
0968:
0969: if (!verticalAlignment.equals(HTML_VERTICAL_ALIGN_TOP)) {
0970: writer.write(" valign=\"");
0971: writer.write(verticalAlignment);
0972: writer.write("\"");
0973: }
0974:
0975: if (text.getRunDirection() == JRPrintText.RUN_DIRECTION_RTL) {
0976: writer.write(" dir=\"rtl\"");
0977: }
0978:
0979: StringBuffer styleBuffer = new StringBuffer();
0980: appendBackcolorStyle(gridCell, styleBuffer);
0981: appendBorderStyle(gridCell.getBox(), styleBuffer);
0982:
0983: String horizontalAlignment = CSS_TEXT_ALIGN_LEFT;
0984:
0985: if (textLength > 0) {
0986: switch (text.getHorizontalAlignment()) {
0987: case JRAlignment.HORIZONTAL_ALIGN_RIGHT: {
0988: horizontalAlignment = CSS_TEXT_ALIGN_RIGHT;
0989: break;
0990: }
0991: case JRAlignment.HORIZONTAL_ALIGN_CENTER: {
0992: horizontalAlignment = CSS_TEXT_ALIGN_CENTER;
0993: break;
0994: }
0995: case JRAlignment.HORIZONTAL_ALIGN_JUSTIFIED: {
0996: horizontalAlignment = CSS_TEXT_ALIGN_JUSTIFY;
0997: break;
0998: }
0999: case JRAlignment.HORIZONTAL_ALIGN_LEFT:
1000: default: {
1001: horizontalAlignment = CSS_TEXT_ALIGN_LEFT;
1002: }
1003: }
1004:
1005: if ((text.getRunDirection() == JRPrintText.RUN_DIRECTION_LTR && !horizontalAlignment
1006: .equals(CSS_TEXT_ALIGN_LEFT))
1007: || (text.getRunDirection() == JRPrintText.RUN_DIRECTION_RTL && !horizontalAlignment
1008: .equals(CSS_TEXT_ALIGN_RIGHT))) {
1009: styleBuffer.append("text-align: ");
1010: styleBuffer.append(horizontalAlignment);
1011: styleBuffer.append(";");
1012: }
1013: }
1014:
1015: if (isWrapBreakWord) {
1016: styleBuffer.append("width: " + gridCell.getWidth()
1017: + sizeUnit + "; ");
1018: styleBuffer.append("word-wrap: break-word; ");
1019: }
1020:
1021: if (text.getLineSpacing() != JRTextElement.LINE_SPACING_SINGLE) {
1022: styleBuffer.append("line-height: "
1023: + text.getLineSpacingFactor() + "; ");
1024: }
1025:
1026: if (styleBuffer.length() > 0) {
1027: writer.write(" style=\"");
1028: writer.write(styleBuffer.toString());
1029: writer.write("\"");
1030: }
1031:
1032: writer.write(">");
1033:
1034: if (text.getAnchorName() != null) {
1035: writer.write("<a name=\"");
1036: writer.write(text.getAnchorName());
1037: writer.write("\"/>");
1038: }
1039:
1040: boolean startedHyperlink = startHyperlink(text);
1041:
1042: if (textLength > 0) {
1043: exportStyledText(styledText);
1044: } else {
1045: writer.write(emptyCellStringProvider
1046: .getStringForEmptyTD(imagesURI));
1047: }
1048:
1049: if (startedHyperlink) {
1050: endHyperlink();
1051: }
1052:
1053: writer.write("</td>\n");
1054: }
1055:
1056: protected boolean startHyperlink(JRPrintHyperlink link)
1057: throws IOException {
1058: String href = getHyperlinkURL(link);
1059:
1060: if (href != null) {
1061: writer.write("<a href=\"");
1062: writer.write(href);
1063: writer.write("\"");
1064:
1065: String target = getHyperlinkTarget(link);
1066: if (target != null) {
1067: writer.write(" target=\"");
1068: writer.write(target);
1069: writer.write("\"");
1070: }
1071:
1072: if (link.getHyperlinkTooltip() != null) {
1073: writer.write(" title=\"");
1074: writer.write(JRStringUtil.xmlEncode(link
1075: .getHyperlinkTooltip()));
1076: writer.write("\"");
1077: }
1078:
1079: writer.write(">");
1080: }
1081:
1082: return href != null;
1083: }
1084:
1085: protected String getHyperlinkTarget(JRPrintHyperlink link) {
1086: String target = null;
1087: switch (link.getHyperlinkTarget()) {
1088: case JRHyperlink.HYPERLINK_TARGET_BLANK: {
1089: target = "_blank";
1090: break;
1091: }
1092: case JRHyperlink.HYPERLINK_TARGET_SELF:
1093: default: {
1094: break;
1095: }
1096: }
1097: return target;
1098: }
1099:
1100: protected String getHyperlinkURL(JRPrintHyperlink link) {
1101: String href = null;
1102: JRHyperlinkProducer customHandler = getCustomHandler(link);
1103: if (customHandler == null) {
1104: switch (link.getHyperlinkType()) {
1105: case JRHyperlink.HYPERLINK_TYPE_REFERENCE: {
1106: if (link.getHyperlinkReference() != null) {
1107: href = link.getHyperlinkReference();
1108: }
1109: break;
1110: }
1111: case JRHyperlink.HYPERLINK_TYPE_LOCAL_ANCHOR: {
1112: if (link.getHyperlinkAnchor() != null) {
1113: href = "#" + link.getHyperlinkAnchor();
1114: }
1115: break;
1116: }
1117: case JRHyperlink.HYPERLINK_TYPE_LOCAL_PAGE: {
1118: if (link.getHyperlinkPage() != null) {
1119: href = "#" + JR_PAGE_ANCHOR_PREFIX + reportIndex
1120: + "_" + link.getHyperlinkPage().toString();
1121: }
1122: break;
1123: }
1124: case JRHyperlink.HYPERLINK_TYPE_REMOTE_ANCHOR: {
1125: if (link.getHyperlinkReference() != null
1126: && link.getHyperlinkAnchor() != null) {
1127: href = link.getHyperlinkReference() + "#"
1128: + link.getHyperlinkAnchor();
1129: }
1130: break;
1131: }
1132: case JRHyperlink.HYPERLINK_TYPE_REMOTE_PAGE: {
1133: if (link.getHyperlinkReference() != null
1134: && link.getHyperlinkPage() != null) {
1135: href = link.getHyperlinkReference() + "#"
1136: + JR_PAGE_ANCHOR_PREFIX + "0_"
1137: + link.getHyperlinkPage().toString();
1138: }
1139: break;
1140: }
1141: case JRHyperlink.HYPERLINK_TYPE_NONE:
1142: default: {
1143: break;
1144: }
1145: }
1146: } else {
1147: href = customHandler.getHyperlink(link);
1148: }
1149:
1150: return href;
1151: }
1152:
1153: protected JRHyperlinkProducer getCustomHandler(JRPrintHyperlink link) {
1154: return hyperlinkProducerFactory == null ? null
1155: : hyperlinkProducerFactory.getHandler(link
1156: .getLinkType());
1157: }
1158:
1159: protected void endHyperlink() throws IOException {
1160: writer.write("</a>");
1161: }
1162:
1163: protected void appendBorderStyle(JRBox box, StringBuffer styleBuffer) {
1164: if (box != null) {
1165: appendBorder(styleBuffer, box.getTopBorder(), box
1166: .getTopBorderColor(), box.getTopPadding(), "top");
1167: appendBorder(styleBuffer, box.getLeftBorder(), box
1168: .getLeftBorderColor(), box.getLeftPadding(), "left");
1169: appendBorder(styleBuffer, box.getBottomBorder(), box
1170: .getBottomBorderColor(), box.getBottomPadding(),
1171: "bottom");
1172: appendBorder(styleBuffer, box.getRightBorder(), box
1173: .getRightBorderColor(), box.getRightPadding(),
1174: "right");
1175: }
1176: }
1177:
1178: protected Color appendBackcolorStyle(JRExporterGridCell gridCell,
1179: StringBuffer styleBuffer) {
1180: Color cellBackcolor = gridCell.getCellBackcolor();
1181: if (cellBackcolor != null
1182: && (backcolor == null || cellBackcolor.getRGB() != backcolor
1183: .getRGB())) {
1184: styleBuffer.append("background-color: #");
1185: styleBuffer.append(JRColorUtil.getColorHexa(cellBackcolor));
1186: styleBuffer.append("; ");
1187:
1188: return backcolor;
1189: }
1190:
1191: return null;
1192: }
1193:
1194: /**
1195: *
1196: */
1197: protected void exportImage(JRPrintImage image,
1198: JRExporterGridCell gridCell) throws JRException,
1199: IOException {
1200: writeCellTDStart(gridCell);
1201:
1202: String horizontalAlignment = CSS_TEXT_ALIGN_LEFT;
1203:
1204: switch (image.getHorizontalAlignment()) {
1205: case JRAlignment.HORIZONTAL_ALIGN_RIGHT: {
1206: horizontalAlignment = CSS_TEXT_ALIGN_RIGHT;
1207: break;
1208: }
1209: case JRAlignment.HORIZONTAL_ALIGN_CENTER: {
1210: horizontalAlignment = CSS_TEXT_ALIGN_CENTER;
1211: break;
1212: }
1213: case JRAlignment.HORIZONTAL_ALIGN_LEFT:
1214: default: {
1215: horizontalAlignment = CSS_TEXT_ALIGN_LEFT;
1216: }
1217: }
1218:
1219: if (!horizontalAlignment.equals(CSS_TEXT_ALIGN_LEFT)) {
1220: writer.write(" align=\"");
1221: writer.write(horizontalAlignment);
1222: writer.write("\"");
1223: }
1224:
1225: String verticalAlignment = HTML_VERTICAL_ALIGN_TOP;
1226:
1227: switch (image.getVerticalAlignment()) {
1228: case JRAlignment.VERTICAL_ALIGN_BOTTOM: {
1229: verticalAlignment = HTML_VERTICAL_ALIGN_BOTTOM;
1230: break;
1231: }
1232: case JRAlignment.VERTICAL_ALIGN_MIDDLE: {
1233: verticalAlignment = HTML_VERTICAL_ALIGN_MIDDLE;
1234: break;
1235: }
1236: case JRAlignment.VERTICAL_ALIGN_TOP:
1237: default: {
1238: verticalAlignment = HTML_VERTICAL_ALIGN_TOP;
1239: }
1240: }
1241:
1242: if (!verticalAlignment.equals(HTML_VERTICAL_ALIGN_TOP)) {
1243: writer.write(" valign=\"");
1244: writer.write(verticalAlignment);
1245: writer.write("\"");
1246: }
1247:
1248: StringBuffer styleBuffer = new StringBuffer();
1249: appendBackcolorStyle(gridCell, styleBuffer);
1250: appendBorderStyle(gridCell.getBox(), styleBuffer);
1251:
1252: if (styleBuffer.length() > 0) {
1253: writer.write(" style=\"");
1254: writer.write(styleBuffer.toString());
1255: writer.write("\"");
1256: }
1257:
1258: writer.write(">");
1259:
1260: if (image.getAnchorName() != null) {
1261: writer.write("<a name=\"");
1262: writer.write(image.getAnchorName());
1263: writer.write("\"/>");
1264: }
1265:
1266: JRRenderable renderer = image.getRenderer();
1267: JRRenderable originalRenderer = renderer;
1268: boolean imageMapRenderer = renderer != null
1269: && renderer instanceof JRImageMapRenderer;
1270:
1271: boolean startedHyperlink = false;
1272:
1273: if (renderer != null || isUsingImagesToAlign) {
1274: startedHyperlink = !imageMapRenderer
1275: && startHyperlink(image);
1276: writer.write("<img");
1277: String imagePath = null;
1278: String imageMapName = null;
1279: List imageMapAreas = null;
1280:
1281: byte scaleImage = image.getScaleImage();
1282: if (renderer != null) {
1283: if (renderer.getType() == JRRenderable.TYPE_IMAGE
1284: && rendererToImagePathMap.containsKey(renderer
1285: .getId())) {
1286: imagePath = (String) rendererToImagePathMap
1287: .get(renderer.getId());
1288: } else {
1289: if (image.isLazy()) {
1290: imagePath = ((JRImageRenderer) renderer)
1291: .getImageLocation();
1292: } else {
1293: JRPrintElementIndex imageIndex = getElementIndex(gridCell);
1294: imagesToProcess.add(imageIndex);
1295:
1296: String imageName = getImageName(imageIndex);
1297: imagePath = imagesURI + imageName;
1298:
1299: //backward compatibility with the IMAGE_MAP parameter
1300: if (imageNameToImageDataMap != null) {
1301: if (renderer.getType() == JRRenderable.TYPE_SVG) {
1302: renderer = new JRWrappingSvgRenderer(
1303: renderer, new Dimension(image
1304: .getWidth(), image
1305: .getHeight()),
1306: JRElement.MODE_OPAQUE == image
1307: .getMode() ? image
1308: .getBackcolor() : null);
1309: }
1310: imageNameToImageDataMap.put(imageName,
1311: renderer.getImageData());
1312: }
1313: //END - backward compatibility with the IMAGE_MAP parameter
1314: }
1315:
1316: rendererToImagePathMap.put(renderer.getId(),
1317: imagePath);
1318: }
1319:
1320: if (imageMapRenderer) {
1321: Rectangle renderingArea = new Rectangle(image
1322: .getWidth(), image.getHeight());
1323:
1324: if (renderer.getType() == JRRenderable.TYPE_IMAGE) {
1325: imageMapName = (String) imageMaps.get(new Pair(
1326: renderer.getId(), renderingArea));
1327: }
1328:
1329: if (imageMapName == null) {
1330: imageMapName = "map_"
1331: + getElementIndex(gridCell).toString();
1332: imageMapAreas = ((JRImageMapRenderer) originalRenderer)
1333: .getImageAreaHyperlinks(renderingArea);
1334:
1335: if (renderer.getType() == JRRenderable.TYPE_IMAGE) {
1336: imageMaps.put(new Pair(renderer.getId(),
1337: renderingArea), imageMapName);
1338: }
1339: }
1340: }
1341: } else // ie: if(isUsingImagesToAlign)
1342: {
1343: loadPxImage();
1344: imagePath = imagesURI + "px";
1345: scaleImage = JRImage.SCALE_IMAGE_FILL_FRAME;
1346: }
1347:
1348: writer.write(" src=\"");
1349: if (imagePath != null)
1350: writer.write(imagePath);
1351: writer.write("\"");
1352:
1353: int borderWidth = 0;
1354: switch (image.getPen()) {
1355: case JRGraphicElement.PEN_DOTTED: {
1356: borderWidth = 1;
1357: break;
1358: }
1359: case JRGraphicElement.PEN_4_POINT: {
1360: borderWidth = 4;
1361: break;
1362: }
1363: case JRGraphicElement.PEN_2_POINT: {
1364: borderWidth = 2;
1365: break;
1366: }
1367: case JRGraphicElement.PEN_NONE: {
1368: borderWidth = 0;
1369: break;
1370: }
1371: case JRGraphicElement.PEN_THIN: {
1372: borderWidth = 1;
1373: break;
1374: }
1375: case JRGraphicElement.PEN_1_POINT:
1376: default: {
1377: borderWidth = 1;
1378: break;
1379: }
1380: }
1381:
1382: writer.write(" border=\"");
1383: writer.write(String.valueOf(borderWidth));
1384: writer.write("\"");
1385:
1386: int imageWidth = image.getWidth() - image.getLeftPadding()
1387: - image.getRightPadding();
1388: if (imageWidth < 0) {
1389: imageWidth = 0;
1390: }
1391:
1392: int imageHeight = image.getHeight() - image.getTopPadding()
1393: - image.getBottomPadding();
1394: if (imageHeight < 0) {
1395: imageHeight = 0;
1396: }
1397:
1398: switch (scaleImage) {
1399: case JRImage.SCALE_IMAGE_FILL_FRAME: {
1400: writer.write(" style=\"width: ");
1401: writer.write(String.valueOf(imageWidth));
1402: writer.write(sizeUnit);
1403: writer.write("; height: ");
1404: writer.write(String.valueOf(imageHeight));
1405: writer.write(sizeUnit);
1406: writer.write("\"");
1407:
1408: break;
1409: }
1410: case JRImage.SCALE_IMAGE_CLIP: //FIXMEIMAGE image clip could be achieved by cutting the image and preserving the image type
1411: case JRImage.SCALE_IMAGE_RETAIN_SHAPE:
1412: default: {
1413: double normalWidth = imageWidth;
1414: double normalHeight = imageHeight;
1415:
1416: if (!image.isLazy()) {
1417: // Image load might fail.
1418: JRRenderable tmpRenderer = JRImageRenderer
1419: .getOnErrorRendererForDimension(renderer,
1420: image.getOnErrorType());
1421: Dimension2D dimension = tmpRenderer == null ? null
1422: : tmpRenderer.getDimension();
1423: // If renderer was replaced, ignore image dimension.
1424: if (tmpRenderer == renderer && dimension != null) {
1425: normalWidth = dimension.getWidth();
1426: normalHeight = dimension.getHeight();
1427: }
1428: }
1429:
1430: if (imageHeight > 0) {
1431: double ratio = normalWidth / normalHeight;
1432:
1433: if (ratio > (double) imageWidth
1434: / (double) imageHeight) {
1435: writer.write(" style=\"width: ");
1436: writer.write(String.valueOf(imageWidth));
1437: writer.write(sizeUnit);
1438: writer.write("\"");
1439: } else {
1440: writer.write(" style=\"height: ");
1441: writer.write(String.valueOf(imageHeight));
1442: writer.write(sizeUnit);
1443: writer.write("\"");
1444: }
1445: }
1446: }
1447: }
1448:
1449: if (imageMapName != null) {
1450: writer.write(" usemap=\"#" + imageMapName + "\"");
1451: }
1452:
1453: writer.write(" alt=\"\"/>");
1454:
1455: if (startedHyperlink) {
1456: endHyperlink();
1457: }
1458:
1459: if (imageMapAreas != null) {
1460: writer.write("\n");
1461: writeImageMap(imageMapName, image, imageMapAreas);
1462: }
1463: }
1464: writer.write("</td>\n");
1465: }
1466:
1467: protected JRPrintElementIndex getElementIndex(
1468: JRExporterGridCell gridCell) {
1469: JRPrintElementIndex imageIndex = new JRPrintElementIndex(
1470: reportIndex, pageIndex, gridCell.getWrapper()
1471: .getAddress());
1472: return imageIndex;
1473: }
1474:
1475: protected void writeImageMap(String imageMapName,
1476: JRPrintImage image, List imageMapAreas) throws IOException {
1477: writer.write("<map name=\"" + imageMapName + "\">\n");
1478:
1479: for (Iterator it = imageMapAreas.iterator(); it.hasNext();) {
1480: JRPrintImageAreaHyperlink areaHyperlink = (JRPrintImageAreaHyperlink) it
1481: .next();
1482: JRPrintImageArea area = areaHyperlink.getArea();
1483:
1484: writer.write(" <area shape=\""
1485: + JRPrintImageArea.getHtmlShape(area.getShape())
1486: + "\"");
1487: writeImageAreaCoordinates(area.getCoordinates());
1488: writeImageAreaHyperlink(areaHyperlink.getHyperlink());
1489: writer.write("/>\n");
1490: }
1491:
1492: if (image.getHyperlinkType() != JRHyperlink.HYPERLINK_TYPE_NONE) {
1493: writer.write(" <area shape=\"default\"");
1494: writeImageAreaCoordinates(new int[] { 0, 0,
1495: image.getWidth(), image.getHeight() });//for IE
1496: writeImageAreaHyperlink(image);
1497: writer.write("/>\n");
1498: }
1499:
1500: writer.write("</map>\n");
1501: }
1502:
1503: protected void writeImageAreaCoordinates(int[] coords)
1504: throws IOException {
1505: if (coords != null && coords.length > 0) {
1506: StringBuffer coordsEnum = new StringBuffer(
1507: coords.length * 4);
1508: coordsEnum.append(coords[0]);
1509: for (int i = 1; i < coords.length; i++) {
1510: coordsEnum.append(',');
1511: coordsEnum.append(coords[i]);
1512: }
1513: writer.write(" coords=\"" + coordsEnum + "\"");
1514: }
1515: }
1516:
1517: protected void writeImageAreaHyperlink(JRPrintHyperlink hyperlink)
1518: throws IOException {
1519: String href = getHyperlinkURL(hyperlink);
1520: if (href == null) {
1521: writer.write(" nohref=\"nohref\"");
1522: } else {
1523: writer.write(" href=\"" + href + "\"");
1524:
1525: String target = getHyperlinkTarget(hyperlink);
1526: if (target != null) {
1527: writer.write(" target=\"");
1528: writer.write(target);
1529: writer.write("\"");
1530: }
1531: }
1532:
1533: if (hyperlink.getHyperlinkTooltip() != null) {
1534: writer.write(" title=\"");
1535: writer.write(JRStringUtil.xmlEncode(hyperlink
1536: .getHyperlinkTooltip()));
1537: writer.write("\"");
1538: }
1539: }
1540:
1541: /**
1542: *
1543: */
1544: protected void loadPxImage() throws JRException {
1545: isPxImageLoaded = true;
1546: //backward compatibility with the IMAGE_MAP parameter
1547: if (imageNameToImageDataMap != null
1548: && !imageNameToImageDataMap.containsKey("px")) {
1549: JRRenderable pxRenderer = JRImageRenderer
1550: .getInstance("net/sf/jasperreports/engine/images/pixel.GIF");
1551: rendererToImagePathMap.put(pxRenderer.getId(), imagesURI
1552: + "px");
1553: imageNameToImageDataMap
1554: .put("px", pxRenderer.getImageData());
1555: }
1556: //END - backward compatibility with the IMAGE_MAP parameter
1557: }
1558:
1559: /**
1560: *
1561: */
1562: protected static interface StringProvider {
1563:
1564: /**
1565: *
1566: */
1567: public String getStringForCollapsedTD(Object value, int width,
1568: int height, String sizeUnit);
1569:
1570: /**
1571: *
1572: */
1573: public String getStringForEmptyTD(Object value);
1574:
1575: }
1576:
1577: /**
1578: *
1579: */
1580: private void appendBorder(StringBuffer sb, byte pen,
1581: Color borderColor, int padding, String side) {
1582: String borderStyle = null;
1583: String borderWidth = null;
1584:
1585: switch (pen) {
1586: case JRGraphicElement.PEN_DOTTED: {
1587: borderStyle = "dashed";
1588: borderWidth = "1";
1589: break;
1590: }
1591: case JRGraphicElement.PEN_4_POINT: {
1592: borderStyle = "solid";
1593: borderWidth = "4";
1594: break;
1595: }
1596: case JRGraphicElement.PEN_2_POINT: {
1597: borderStyle = "solid";
1598: borderWidth = "2";
1599: break;
1600: }
1601: case JRGraphicElement.PEN_THIN: {
1602: borderStyle = "solid";
1603: borderWidth = "1";
1604: break;
1605: }
1606: case JRGraphicElement.PEN_NONE: {
1607: break;
1608: }
1609: case JRGraphicElement.PEN_1_POINT:
1610: default: {
1611: borderStyle = "solid";
1612: borderWidth = "1";
1613: break;
1614: }
1615: }
1616:
1617: if (borderWidth != null) {
1618: sb.append("border-");
1619: sb.append(side);
1620: sb.append("-style: ");
1621: sb.append(borderStyle);
1622: sb.append("; ");
1623:
1624: sb.append("border-");
1625: sb.append(side);
1626: sb.append("-width: ");
1627: sb.append(borderWidth);
1628: sb.append(sizeUnit);
1629: sb.append("; ");
1630:
1631: sb.append("border-");
1632: sb.append(side);
1633: sb.append("-color: #");
1634: sb.append(JRColorUtil.getColorHexa(borderColor));
1635: sb.append("; ");
1636: }
1637:
1638: if (padding > 0) {
1639: sb.append("padding-");
1640: sb.append(side);
1641: sb.append(": ");
1642: sb.append(padding);
1643: sb.append(sizeUnit);
1644: sb.append("; ");
1645: }
1646: }
1647:
1648: /**
1649: *
1650: */
1651: public static String getImageName(
1652: JRPrintElementIndex printElementIndex) {
1653: return IMAGE_NAME_PREFIX + printElementIndex.toString();
1654: }
1655:
1656: /**
1657: *
1658: */
1659: public static JRPrintElementIndex getPrintElementIndex(
1660: String imageName) {
1661: if (!imageName.startsWith(IMAGE_NAME_PREFIX)) {
1662: throw new JRRuntimeException("Invalid image name: "
1663: + imageName);
1664: }
1665:
1666: return JRPrintElementIndex.parsePrintElementIndex(imageName
1667: .substring(IMAGE_NAME_PREFIX_LEGTH));
1668: }
1669:
1670: protected void exportFrame(JRPrintFrame frame,
1671: JRExporterGridCell gridCell) throws IOException,
1672: JRException {
1673: writeCellTDStart(gridCell);
1674:
1675: StringBuffer styleBuffer = new StringBuffer();
1676: Color frameBackcolor = appendBackcolorStyle(gridCell,
1677: styleBuffer);
1678: appendBorderStyle(gridCell.getBox(), styleBuffer);
1679:
1680: if (styleBuffer.length() > 0) {
1681: writer.write(" style=\"");
1682: writer.write(styleBuffer.toString());
1683: writer.write("\"");
1684: }
1685:
1686: writer.write(">\n");
1687:
1688: if (frameBackcolor != null) {
1689: setBackcolor(frameBackcolor);
1690: }
1691: try {
1692: exportGrid(gridCell.getLayout(), false);
1693: } finally {
1694: if (frameBackcolor != null) {
1695: restoreBackcolor();
1696: }
1697: }
1698:
1699: writer.write("</td>\n");
1700: }
1701:
1702: protected void setBackcolor(Color color) {
1703: backcolorStack.addLast(backcolor);
1704:
1705: backcolor = color;
1706: }
1707:
1708: protected void restoreBackcolor() {
1709: backcolor = (Color) backcolorStack.removeLast();
1710: }
1711:
1712: }
|