001: /*
002: * ============================================================================
003: * GNU Lesser General Public License
004: * ============================================================================
005: *
006: * JasperReports - Free Java report-generating library.
007: * Copyright (C) 2001-2006 JasperSoft Corporation http://www.jaspersoft.com
008: *
009: * This library is free software; you can redistribute it and/or
010: * modify it under the terms of the GNU Lesser General Public
011: * License as published by the Free Software Foundation; either
012: * 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,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017: * Lesser General Public License for more details.
018: *
019: * You should have received a copy of the GNU Lesser General Public
020: * License along with this library; if not, write to the Free Software
021: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
022: *
023: * JasperSoft Corporation
024: * 303 Second Street, Suite 450 North
025: * San Francisco, CA 94107
026: * http://www.jaspersoft.com
027: */
028:
029: /*
030: * Contributors:
031: * Eugene D - eugenedruy@users.sourceforge.net
032: * Adrian Jackson - iapetus@users.sourceforge.net
033: * David Taylor - exodussystems@users.sourceforge.net
034: * Lars Kristensen - llk@users.sourceforge.net
035: */
036: package net.sf.jasperreports.engine.export;
037:
038: import java.awt.BasicStroke;
039: import java.awt.Color;
040: import java.awt.Graphics2D;
041: import java.awt.Rectangle;
042: import java.awt.RenderingHints;
043: import java.awt.Shape;
044: import java.awt.Stroke;
045: import java.awt.geom.AffineTransform;
046: import java.awt.geom.Dimension2D;
047: import java.util.Collection;
048: import java.util.Iterator;
049:
050: import net.sf.jasperreports.engine.JRAbstractExporter;
051: import net.sf.jasperreports.engine.JRAlignment;
052: import net.sf.jasperreports.engine.JRBox;
053: import net.sf.jasperreports.engine.JRElement;
054: import net.sf.jasperreports.engine.JRException;
055: import net.sf.jasperreports.engine.JRExporterParameter;
056: import net.sf.jasperreports.engine.JRGraphicElement;
057: import net.sf.jasperreports.engine.JRImage;
058: import net.sf.jasperreports.engine.JRImageRenderer;
059: import net.sf.jasperreports.engine.JRLine;
060: import net.sf.jasperreports.engine.JRPrintElement;
061: import net.sf.jasperreports.engine.JRPrintEllipse;
062: import net.sf.jasperreports.engine.JRPrintFrame;
063: import net.sf.jasperreports.engine.JRPrintImage;
064: import net.sf.jasperreports.engine.JRPrintLine;
065: import net.sf.jasperreports.engine.JRPrintPage;
066: import net.sf.jasperreports.engine.JRPrintRectangle;
067: import net.sf.jasperreports.engine.JRPrintText;
068: import net.sf.jasperreports.engine.JRRenderable;
069: import net.sf.jasperreports.engine.JRTextElement;
070: import net.sf.jasperreports.engine.util.JRGraphEnvInitializer;
071: import net.sf.jasperreports.engine.util.JRProperties;
072: import net.sf.jasperreports.engine.util.JRStyledText;
073:
074: /**
075: * Exports a JasperReports document to a <tt>Graphics2D</tt> object. Since all font measurement and layout
076: * calculation during report filling is done using AWT, this is considered the perfect exporter, unlike the others,
077: * which are only approximations of the initial document.
078: * <p>
079: * As its name indicates, this exporter is special because it does not produce files or does not send character
080: * or binary data to an output stream.
081: * @author Teodor Danciu (teodord@users.sourceforge.net)
082: * @version $Id: JRGraphics2DExporter.java 1811 2007-08-13 19:52:07Z teodord $
083: */
084: public class JRGraphics2DExporter extends JRAbstractExporter {
085:
086: private static final int ELEMENT_RECTANGLE_PADDING = 3;
087: private static final float DEFAULT_ZOOM = 1f;
088:
089: /**
090: * Property that provides a default value for the
091: * {@link net.sf.jasperreports.engine.export.JRGraphics2DExporterParameter#MINIMIZE_PRINTER_JOB_SIZE JRGraphics2DExporterParameter.MINIMIZE_PRINTER_JOB_SIZE}
092: * Graphics2D exporter parameter.
093: *
094: * @see net.sf.jasperreports.engine.export.JRGraphics2DExporterParameter#MINIMIZE_PRINTER_JOB_SIZE
095: */
096: public static final String MINIMIZE_PRINTER_JOB_SIZE = JRProperties.PROPERTY_PREFIX
097: + "export.graphics2d.min.job.size";
098:
099: /**
100: *
101: */
102: protected Graphics2D grx = null;
103: protected JRExportProgressMonitor progressMonitor = null;
104: protected float zoom = DEFAULT_ZOOM;
105:
106: protected TextRenderer textRenderer = null;
107:
108: /**
109: *
110: */
111: public JRGraphics2DExporter() throws JRException {
112: JRGraphEnvInitializer.initializeGraphEnv();
113: }
114:
115: /**
116: *
117: */
118: public void exportReport() throws JRException {
119: progressMonitor = (JRExportProgressMonitor) parameters
120: .get(JRExporterParameter.PROGRESS_MONITOR);
121:
122: /* */
123: setOffset();
124:
125: try {
126: /* */
127: setExportContext();
128:
129: /* */
130: setInput();
131:
132: /* */
133: setPageRange();
134:
135: /* */
136: setTextRenderer();
137:
138: grx = (Graphics2D) parameters
139: .get(JRGraphics2DExporterParameter.GRAPHICS_2D);
140: if (grx == null) {
141: throw new JRException(
142: "No output specified for the exporter. java.awt.Graphics2D object expected.");
143: }
144:
145: Float zoomRatio = (Float) parameters
146: .get(JRGraphics2DExporterParameter.ZOOM_RATIO);
147: if (zoomRatio != null) {
148: zoom = zoomRatio.floatValue();
149: if (zoom <= 0) {
150: throw new JRException("Invalid zoom ratio : "
151: + zoom);
152: }
153: } else {
154: zoom = DEFAULT_ZOOM;
155: }
156:
157: exportReportToGraphics2D();
158: } finally {
159: resetExportContext();
160: }
161: }
162:
163: protected void setTextRenderer() {
164: boolean isMinimizePrinterJobSize = true;
165: Boolean isMinimizePrinterJobSizeParam = (Boolean) parameters
166: .get(JRGraphics2DExporterParameter.MINIMIZE_PRINTER_JOB_SIZE);
167: if (isMinimizePrinterJobSizeParam == null) {
168: isMinimizePrinterJobSize = JRProperties
169: .getBooleanProperty(MINIMIZE_PRINTER_JOB_SIZE);
170: } else {
171: isMinimizePrinterJobSize = isMinimizePrinterJobSizeParam
172: .booleanValue();
173: }
174:
175: textRenderer = new TextRenderer(isMinimizePrinterJobSize);
176: }
177:
178: /**
179: *
180: */
181: public void exportReportToGraphics2D() throws JRException {
182: grx.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
183: RenderingHints.VALUE_ANTIALIAS_ON);
184: //grx.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
185: grx.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
186: RenderingHints.VALUE_FRACTIONALMETRICS_ON);
187: grx.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
188: RenderingHints.VALUE_INTERPOLATION_BICUBIC);
189:
190: AffineTransform atrans = new AffineTransform();
191: atrans.translate(globalOffsetX, globalOffsetY);
192: atrans.scale(zoom, zoom);
193: grx.transform(atrans);
194:
195: java.util.List pages = jasperPrint.getPages();
196: if (pages != null) {
197: Shape oldClipShape = grx.getClip();
198:
199: grx.clip(new Rectangle(0, 0, jasperPrint.getPageWidth(),
200: jasperPrint.getPageHeight()));
201:
202: try {
203: JRPrintPage page = (JRPrintPage) pages
204: .get(startPageIndex);
205: exportPage(page);
206: } finally {
207: grx.setClip(oldClipShape);
208: }
209: }
210: }
211:
212: /**
213: *
214: */
215: protected void exportPage(JRPrintPage page) throws JRException {
216: grx.setColor(Color.white);
217: grx.fillRect(0, 0, jasperPrint.getPageWidth(), jasperPrint
218: .getPageHeight());
219:
220: grx.setColor(Color.black);
221: grx.setStroke(new BasicStroke(1));
222:
223: /* */
224: Collection elements = page.getElements();
225: exportElements(elements);
226:
227: if (progressMonitor != null) {
228: progressMonitor.afterPageExport();
229: }
230: }
231:
232: protected void exportElements(Collection elements)
233: throws JRException {
234: if (elements != null && elements.size() > 0) {
235: Shape clipArea = grx.getClip();
236: for (Iterator it = elements.iterator(); it.hasNext();) {
237: JRPrintElement element = (JRPrintElement) it.next();
238:
239: if (!clipArea.intersects(element.getX() + getOffsetX()
240: - ELEMENT_RECTANGLE_PADDING, element.getY()
241: + getOffsetY() - ELEMENT_RECTANGLE_PADDING,
242: element.getWidth() + 2
243: * ELEMENT_RECTANGLE_PADDING, element
244: .getHeight()
245: + 2 * ELEMENT_RECTANGLE_PADDING)) {
246: continue;
247: }
248:
249: if (element instanceof JRPrintLine) {
250: exportLine((JRPrintLine) element);
251: } else if (element instanceof JRPrintRectangle) {
252: exportRectangle((JRPrintRectangle) element);
253: } else if (element instanceof JRPrintEllipse) {
254: exportEllipse((JRPrintEllipse) element);
255: } else if (element instanceof JRPrintImage) {
256: exportImage((JRPrintImage) element);
257: } else if (element instanceof JRPrintText) {
258: exportText((JRPrintText) element);
259: } else if (element instanceof JRPrintFrame) {
260: exportFrame((JRPrintFrame) element);
261: }
262: }
263: }
264: }
265:
266: /**
267: *
268: */
269: protected void exportLine(JRPrintLine line) {
270: grx.setColor(line.getForecolor());
271:
272: Stroke stroke = getStroke(line.getPen());
273:
274: if (stroke != null) {
275: grx.setStroke(stroke);
276:
277: grx.translate(.5, .5);
278:
279: if (line.getDirection() == JRLine.DIRECTION_TOP_DOWN) {
280: grx.drawLine(line.getX() + getOffsetX(), line.getY()
281: + getOffsetY(), line.getX() + getOffsetX()
282: + line.getWidth() - 1, line.getY()
283: + getOffsetY() + line.getHeight() - 1);
284: } else {
285: grx.drawLine(line.getX() + getOffsetX(), line.getY()
286: + getOffsetY() + line.getHeight() - 1, line
287: .getX()
288: + getOffsetX() + line.getWidth() - 1, line
289: .getY()
290: + getOffsetY());
291: }
292:
293: grx.translate(-.5, -.5);
294: }
295: }
296:
297: /**
298: *
299: */
300: protected void exportRectangle(JRPrintRectangle rectangle) {
301: if (rectangle.getMode() == JRElement.MODE_OPAQUE) {
302: grx.setColor(rectangle.getBackcolor());
303: if (rectangle.getRadius() > 0) {
304: grx.fillRoundRect(rectangle.getX() + getOffsetX(),
305: rectangle.getY() + getOffsetY(), rectangle
306: .getWidth(), rectangle.getHeight(),
307: 2 * rectangle.getRadius(), 2 * rectangle
308: .getRadius());
309: } else {
310: grx.fillRect(rectangle.getX() + getOffsetX(), rectangle
311: .getY()
312: + getOffsetY(), rectangle.getWidth(), rectangle
313: .getHeight());
314: }
315: }
316:
317: grx.setColor(rectangle.getForecolor());
318:
319: byte pen = rectangle.getPen();
320: Stroke stroke = getStroke(pen);
321:
322: if (stroke != null) {
323: double cornerOffset = getBorderCornerOffset(pen);
324: int sizeAdjust = getRectangleSizeAdjust(pen);
325:
326: AffineTransform transform = grx.getTransform();
327:
328: grx.translate(rectangle.getX() + getOffsetX()
329: + cornerOffset, rectangle.getY() + getOffsetY()
330: + cornerOffset);
331: if (pen == JRGraphicElement.PEN_THIN) {
332: grx.scale((rectangle.getWidth() - .5)
333: / rectangle.getWidth(),
334: (rectangle.getHeight() - .5)
335: / rectangle.getHeight());
336: }
337:
338: grx.setStroke(stroke);
339:
340: if (rectangle.getRadius() > 0) {
341: grx.drawRoundRect(0, 0, rectangle.getWidth()
342: - sizeAdjust, rectangle.getHeight()
343: - sizeAdjust, 2 * rectangle.getRadius(),
344: 2 * rectangle.getRadius());
345: } else {
346: grx.drawRect(0, 0, rectangle.getWidth() - sizeAdjust,
347: rectangle.getHeight() - sizeAdjust);
348: }
349:
350: grx.setTransform(transform);
351: }
352: }
353:
354: private static int getRectangleSizeAdjust(byte pen) {
355: switch (pen) {
356: case JRGraphicElement.PEN_1_POINT:
357: case JRGraphicElement.PEN_DOTTED:
358: return 1;
359: default:
360: return 0;
361: }
362: }
363:
364: /**
365: *
366: */
367: protected void exportEllipse(JRPrintEllipse ellipse) {
368: if (ellipse.getMode() == JRElement.MODE_OPAQUE) {
369: grx.setColor(ellipse.getBackcolor());
370: grx.fillOval(ellipse.getX() + getOffsetX(), ellipse.getY()
371: + getOffsetY(), ellipse.getWidth(), ellipse
372: .getHeight());
373: }
374:
375: grx.setColor(ellipse.getForecolor());
376:
377: byte pen = ellipse.getPen();
378: Stroke stroke = getStroke(pen);
379:
380: if (stroke != null) {
381: double cornerOffset = getBorderCornerOffset(pen);
382: int sizeAdjust = getRectangleSizeAdjust(pen);
383:
384: AffineTransform transform = grx.getTransform();
385:
386: grx.translate(ellipse.getX() + getOffsetX() + cornerOffset,
387: ellipse.getY() + getOffsetY() + cornerOffset);
388: if (pen == JRGraphicElement.PEN_THIN) {
389: grx.scale((ellipse.getWidth() - .5)
390: / ellipse.getWidth(),
391: (ellipse.getHeight() - .5)
392: / ellipse.getHeight());
393: }
394:
395: grx.setStroke(stroke);
396:
397: grx.drawOval(0, 0, ellipse.getWidth() - sizeAdjust, ellipse
398: .getHeight()
399: - sizeAdjust);
400:
401: grx.setTransform(transform);
402: }
403: }
404:
405: /**
406: *
407: */
408: protected void exportImage(JRPrintImage printImage)
409: throws JRException {
410: if (printImage.getMode() == JRElement.MODE_OPAQUE) {
411: grx.setColor(printImage.getBackcolor());
412:
413: grx.fillRect(printImage.getX() + getOffsetX(), printImage
414: .getY()
415: + getOffsetY(), printImage.getWidth(), printImage
416: .getHeight());
417: }
418:
419: int topPadding = printImage.getTopPadding();
420: int leftPadding = printImage.getLeftPadding();
421: int bottomPadding = printImage.getBottomPadding();
422: int rightPadding = printImage.getRightPadding();
423:
424: int availableImageWidth = printImage.getWidth() - leftPadding
425: - rightPadding;
426: availableImageWidth = (availableImageWidth < 0) ? 0
427: : availableImageWidth;
428:
429: int availableImageHeight = printImage.getHeight() - topPadding
430: - bottomPadding;
431: availableImageHeight = (availableImageHeight < 0) ? 0
432: : availableImageHeight;
433:
434: JRRenderable renderer = printImage.getRenderer();
435:
436: if (renderer != null && availableImageWidth > 0
437: && availableImageHeight > 0) {
438: if (renderer.getType() == JRRenderable.TYPE_IMAGE) {
439: // Image renderers are all asked for their image data and dimension at some point.
440: // Better to test and replace the renderer now, in case of lazy load error.
441: renderer = JRImageRenderer
442: .getOnErrorRendererForImageData(renderer,
443: printImage.getOnErrorType());
444: if (renderer != null) {
445: renderer = JRImageRenderer
446: .getOnErrorRendererForDimension(renderer,
447: printImage.getOnErrorType());
448: }
449: }
450: } else {
451: renderer = null;
452: }
453:
454: if (renderer != null) {
455: int normalWidth = availableImageWidth;
456: int normalHeight = availableImageHeight;
457:
458: Dimension2D dimension = renderer.getDimension();
459: if (dimension != null) {
460: normalWidth = (int) dimension.getWidth();
461: normalHeight = (int) dimension.getHeight();
462: }
463:
464: float xalignFactor = 0f;
465: switch (printImage.getHorizontalAlignment()) {
466: case JRAlignment.HORIZONTAL_ALIGN_RIGHT: {
467: xalignFactor = 1f;
468: break;
469: }
470: case JRAlignment.HORIZONTAL_ALIGN_CENTER: {
471: xalignFactor = 0.5f;
472: break;
473: }
474: case JRAlignment.HORIZONTAL_ALIGN_LEFT:
475: default: {
476: xalignFactor = 0f;
477: break;
478: }
479: }
480:
481: float yalignFactor = 0f;
482: switch (printImage.getVerticalAlignment()) {
483: case JRAlignment.VERTICAL_ALIGN_BOTTOM: {
484: yalignFactor = 1f;
485: break;
486: }
487: case JRAlignment.VERTICAL_ALIGN_MIDDLE: {
488: yalignFactor = 0.5f;
489: break;
490: }
491: case JRAlignment.VERTICAL_ALIGN_TOP:
492: default: {
493: yalignFactor = 0f;
494: break;
495: }
496: }
497:
498: switch (printImage.getScaleImage())// FIXME maybe put this in JRFiller
499: {
500: case JRImage.SCALE_IMAGE_CLIP: {
501: int xoffset = (int) (xalignFactor * (availableImageWidth - normalWidth));
502: int yoffset = (int) (yalignFactor * (availableImageHeight - normalHeight));
503:
504: Shape oldClipShape = grx.getClip();
505:
506: grx.clip(new Rectangle(printImage.getX() + leftPadding
507: + getOffsetX(), printImage.getY() + topPadding
508: + getOffsetY(), availableImageWidth,
509: availableImageHeight));
510:
511: try {
512: renderer.render(grx, new Rectangle(printImage
513: .getX()
514: + leftPadding + getOffsetX() + xoffset,
515: printImage.getY() + topPadding
516: + getOffsetY() + yoffset,
517: normalWidth, normalHeight));
518: } finally {
519: grx.setClip(oldClipShape);
520: }
521:
522: break;
523: }
524: case JRImage.SCALE_IMAGE_FILL_FRAME: {
525: renderer.render(grx, new Rectangle(printImage.getX()
526: + leftPadding + getOffsetX(), printImage.getY()
527: + topPadding + getOffsetY(),
528: availableImageWidth, availableImageHeight));
529:
530: break;
531: }
532: case JRImage.SCALE_IMAGE_RETAIN_SHAPE:
533: default: {
534: if (printImage.getHeight() > 0) {
535: double ratio = (double) normalWidth
536: / (double) normalHeight;
537:
538: if (ratio > (double) availableImageWidth
539: / (double) availableImageHeight) {
540: normalWidth = availableImageWidth;
541: normalHeight = (int) (availableImageWidth / ratio);
542: } else {
543: normalWidth = (int) (availableImageHeight * ratio);
544: normalHeight = availableImageHeight;
545: }
546:
547: int xoffset = (int) (xalignFactor * (availableImageWidth - normalWidth));
548: int yoffset = (int) (yalignFactor * (availableImageHeight - normalHeight));
549:
550: renderer.render(grx, new Rectangle(printImage
551: .getX()
552: + leftPadding + getOffsetX() + xoffset,
553: printImage.getY() + topPadding
554: + getOffsetY() + yoffset,
555: normalWidth, normalHeight));
556: }
557:
558: break;
559: }
560: }
561: }
562:
563: if (printImage.getTopBorder() == JRGraphicElement.PEN_NONE
564: && printImage.getLeftBorder() == JRGraphicElement.PEN_NONE
565: && printImage.getBottomBorder() == JRGraphicElement.PEN_NONE
566: && printImage.getRightBorder() == JRGraphicElement.PEN_NONE) {
567: if (printImage.getPen() != JRGraphicElement.PEN_NONE) {
568: exportBox(getBox(printImage), printImage);
569: }
570: } else {
571: exportBox(printImage, printImage);
572: }
573: }
574:
575: /**
576: *
577: */
578: protected void exportText(JRPrintText text) {
579: JRStyledText styledText = getStyledText(text, false);
580:
581: if (styledText == null) {
582: return;
583: }
584:
585: String allText = styledText.getText();
586:
587: int x = text.getX() + getOffsetX();
588: int y = text.getY() + getOffsetY();
589: int width = text.getWidth();
590: int height = text.getHeight();
591: int topPadding = text.getTopPadding();
592: int leftPadding = text.getLeftPadding();
593: int bottomPadding = text.getBottomPadding();
594: int rightPadding = text.getRightPadding();
595:
596: double angle = 0;
597:
598: switch (text.getRotation()) {
599: case JRTextElement.ROTATION_LEFT: {
600: y = text.getY() + getOffsetY() + text.getHeight();
601: width = text.getHeight();
602: height = text.getWidth();
603: int tmpPadding = topPadding;
604: topPadding = leftPadding;
605: leftPadding = bottomPadding;
606: bottomPadding = rightPadding;
607: rightPadding = tmpPadding;
608: angle = -Math.PI / 2;
609: break;
610: }
611: case JRTextElement.ROTATION_RIGHT: {
612: x = text.getX() + getOffsetX() + text.getWidth();
613: width = text.getHeight();
614: height = text.getWidth();
615: int tmpPadding = topPadding;
616: topPadding = rightPadding;
617: rightPadding = bottomPadding;
618: bottomPadding = leftPadding;
619: leftPadding = tmpPadding;
620: angle = Math.PI / 2;
621: break;
622: }
623: case JRTextElement.ROTATION_UPSIDE_DOWN: {
624: int tmpPadding = topPadding;
625: x = text.getX() + getOffsetX() + text.getWidth();
626: y = text.getY() + getOffsetY() + text.getHeight();
627: topPadding = bottomPadding;
628: bottomPadding = tmpPadding;
629: tmpPadding = leftPadding;
630: leftPadding = rightPadding;
631: rightPadding = tmpPadding;
632: angle = Math.PI;
633: break;
634: }
635: case JRTextElement.ROTATION_NONE:
636: default: {
637: }
638: }
639:
640: grx.rotate(angle, x, y);
641:
642: if (text.getMode() == JRElement.MODE_OPAQUE) {
643: grx.setColor(text.getBackcolor());
644: grx.fillRect(x, y, width, height);
645: } else {
646: /*
647: grx.setColor(text.getForecolor());
648: grx.setStroke(new BasicStroke(1));
649: grx.drawRect(x, y, width, height);
650: */
651: }
652:
653: if (allText.length() > 0) {
654: grx.setColor(text.getForecolor());
655:
656: /* */
657: textRenderer.render(grx, x, y, width, height, topPadding,
658: leftPadding, bottomPadding, rightPadding, text
659: .getTextHeight(), text
660: .getHorizontalAlignment(), text
661: .getVerticalAlignment(), text
662: .getLineSpacingFactor(), text
663: .getLeadingOffset(), text.getFontSize(),
664: text.isStyledText(), styledText, allText);
665:
666: }
667:
668: grx.rotate(-angle, x, y);
669:
670: /* */
671: exportBox(text, text);
672: }
673:
674: /**
675: *
676: */
677: protected void exportBox(JRBox box, JRPrintElement element) {
678: Stroke topStroke = null;
679: Stroke leftStroke = null;
680: Stroke bottomStroke = null;
681: Stroke rightStroke = null;
682:
683: if (box != null) {
684: topStroke = getBorderStroke(box.getTopBorder());
685: leftStroke = getBorderStroke(box.getLeftBorder());
686: bottomStroke = getBorderStroke(box.getBottomBorder());
687: rightStroke = getBorderStroke(box.getRightBorder());
688: }
689:
690: if (topStroke != null) {
691: double cornerOffset = getBorderCornerOffset(box
692: .getTopBorder());
693:
694: grx.setStroke(topStroke);
695: grx.setColor(box.getTopBorderColor() == null ? element
696: .getForecolor() : box.getTopBorderColor());
697:
698: grx.translate(0, cornerOffset);
699: grx
700: .drawLine(element.getX() + getOffsetX(), element
701: .getY()
702: + getOffsetY(), element.getX()
703: + getOffsetX() + element.getWidth(),
704: element.getY() + getOffsetY());
705: grx.translate(0, -cornerOffset);
706: }
707:
708: if (leftStroke != null) {
709: double cornerOffset = getBorderCornerOffset(box
710: .getLeftBorder());
711:
712: grx.setStroke(leftStroke);
713: grx.setColor(box.getLeftBorderColor() == null ? element
714: .getForecolor() : box.getLeftBorderColor());
715:
716: grx.translate(cornerOffset, 0);
717: grx
718: .drawLine(element.getX() + getOffsetX(), element
719: .getY()
720: + getOffsetY(), element.getX()
721: + getOffsetX(), element.getY()
722: + getOffsetY() + element.getHeight());
723: grx.translate(-cornerOffset, 0);
724: }
725:
726: if (bottomStroke != null) {
727: double cornerOffset = getBorderCornerOffset(box
728: .getBottomBorder());
729:
730: grx.setStroke(bottomStroke);
731: grx.setColor(box.getBottomBorderColor() == null ? element
732: .getForecolor() : box.getBottomBorderColor());
733:
734: grx.translate(0, -cornerOffset);
735: grx.drawLine(element.getX() + getOffsetX(), element.getY()
736: + getOffsetY() + element.getHeight(), element
737: .getX()
738: + getOffsetX() + element.getWidth(), element.getY()
739: + getOffsetY() + element.getHeight());
740: grx.translate(0, cornerOffset);
741: }
742:
743: if (rightStroke != null) {
744: double cornerOffset = getBorderCornerOffset(box
745: .getRightBorder());
746:
747: grx.setStroke(rightStroke);
748: grx.setColor(box.getRightBorderColor() == null ? element
749: .getForecolor() : box.getRightBorderColor());
750:
751: grx.translate(-cornerOffset, 0);
752: grx
753: .drawLine(element.getX() + getOffsetX()
754: + element.getWidth(), element.getY()
755: + getOffsetY(), element.getX()
756: + getOffsetX() + element.getWidth(),
757: element.getY() + getOffsetY()
758: + element.getHeight());
759: grx.translate(cornerOffset, 0);
760: }
761: }
762:
763: /**
764: *
765: */
766: private static final double THIN_CORNER_OFFSET = 0.25d;
767: private static final double ONE_POINT_CORNER_OFFSET = 0.5d;
768:
769: private static final Stroke STROKE_THIN = new BasicStroke(0.5f);
770: private static final Stroke STROKE_1_POINT = new BasicStroke(1f);
771: private static final Stroke STROKE_2_POINT = new BasicStroke(2f);
772: private static final Stroke STROKE_4_POINT = new BasicStroke(4f);
773: private static final Stroke STROKE_DOTTED = new BasicStroke(1f,
774: BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 10f,
775: new float[] { 5f, 3f }, 0f);
776:
777: private static final Stroke BORDER_STROKE_THIN = new BasicStroke(
778: 0.5f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER);
779: private static final Stroke BORDER_STROKE_1_POINT = new BasicStroke(
780: 1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER);
781: private static final Stroke BORDER_STROKE_DOTTED = new BasicStroke(
782: 1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10f,
783: new float[] { 5f, 3f }, 0f);
784:
785: /**
786: *
787: */
788: private static Stroke getStroke(byte pen) {
789: switch (pen) {
790: case JRGraphicElement.PEN_DOTTED: {
791: return STROKE_DOTTED;
792: }
793: case JRGraphicElement.PEN_4_POINT: {
794: return STROKE_4_POINT;
795: }
796: case JRGraphicElement.PEN_2_POINT: {
797: return STROKE_2_POINT;
798: }
799: case JRGraphicElement.PEN_NONE: {
800: return null;
801: }
802: case JRGraphicElement.PEN_THIN: {
803: return STROKE_THIN;
804: }
805: case JRGraphicElement.PEN_1_POINT:
806: default: {
807: return STROKE_1_POINT;
808: }
809: }
810: }
811:
812: private static Stroke getBorderStroke(byte pen) {
813: switch (pen) {
814: case JRGraphicElement.PEN_DOTTED: {
815: return BORDER_STROKE_DOTTED;
816: }
817: case JRGraphicElement.PEN_4_POINT: {
818: return STROKE_4_POINT;
819: }
820: case JRGraphicElement.PEN_2_POINT: {
821: return STROKE_2_POINT;
822: }
823: case JRGraphicElement.PEN_NONE: {
824: return null;
825: }
826: case JRGraphicElement.PEN_THIN: {
827: return BORDER_STROKE_THIN;
828: }
829: case JRGraphicElement.PEN_1_POINT:
830: default: {
831: return BORDER_STROKE_1_POINT;
832: }
833: }
834: }
835:
836: private static double getBorderCornerOffset(byte pen) {
837: switch (pen) {
838: case JRGraphicElement.PEN_THIN: {
839: return THIN_CORNER_OFFSET;
840: }
841: case JRGraphicElement.PEN_1_POINT:
842: case JRGraphicElement.PEN_DOTTED: {
843: return ONE_POINT_CORNER_OFFSET;
844: }
845: default: {
846: return 0;
847: }
848: }
849: }
850:
851: protected void exportFrame(JRPrintFrame frame) throws JRException {
852: if (frame.getMode() == JRElement.MODE_OPAQUE) {
853: int x = frame.getX() + getOffsetX();
854: int y = frame.getY() + getOffsetY();
855:
856: grx.setColor(frame.getBackcolor());
857: grx.fillRect(x, y, frame.getWidth(), frame.getHeight());
858: }
859:
860: setFrameElementsOffset(frame, false);
861: try {
862: exportElements(frame.getElements());
863: } finally {
864: restoreElementOffsets();
865: }
866:
867: exportBox(frame, frame);
868: }
869:
870: }
|