001: /**
002: * ===========================================
003: * JFreeReport : a free Java reporting library
004: * ===========================================
005: *
006: * Project Info: http://reporting.pentaho.org/
007: *
008: * (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
009: *
010: * This library is free software; you can redistribute it and/or modify it under the terms
011: * of the GNU Lesser General Public License as published by the Free Software Foundation;
012: * either version 2.1 of the License, or (at your option) any later version.
013: *
014: * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
015: * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
016: * See the GNU Lesser General Public License for more details.
017: *
018: * You should have received a copy of the GNU Lesser General Public License along with this
019: * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
020: * Boston, MA 02111-1307, USA.
021: *
022: * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
023: * in the United States and other countries.]
024: *
025: * ------------
026: * HSSFCellStyleProducer.java
027: * ------------
028: * (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
029: */package org.jfree.report.modules.output.table.xls.helper;
030:
031: import java.awt.Color;
032: import java.util.HashMap;
033:
034: import org.apache.poi.hssf.usermodel.HSSFCellStyle;
035: import org.apache.poi.hssf.usermodel.HSSFDataFormat;
036: import org.apache.poi.hssf.usermodel.HSSFFont;
037: import org.apache.poi.hssf.usermodel.HSSFWorkbook;
038: import org.apache.poi.hssf.util.HSSFColor;
039: import org.jfree.report.ElementAlignment;
040: import org.jfree.report.layout.model.BorderEdge;
041: import org.jfree.report.layout.model.RenderBox;
042: import org.jfree.report.modules.output.table.base.TableCellDefinition;
043: import org.jfree.report.style.BorderStyle;
044: import org.jfree.report.style.ElementStyleKeys;
045: import org.jfree.report.style.StyleSheet;
046: import org.jfree.report.style.TextStyleKeys;
047: import org.jfree.report.style.TextWrap;
048: import org.jfree.report.util.geom.StrictGeomUtility;
049: import org.jfree.util.Log;
050:
051: /**
052: * The cellstyle producer converts the JFreeReport content into excel cell
053: * styles. This class is able to use the POI 2.0 features to build data cells.
054: *
055: * @author Thomas Morgner
056: */
057: public class HSSFCellStyleProducer {
058: private static class HSSFCellStyleKey {
059: /**
060: * The cell background color.
061: */
062: private short color;
063:
064: /**
065: * The top border's size.
066: */
067: private short borderStrokeTop;
068:
069: /**
070: * The bottom border's size.
071: */
072: private short borderStrokeBottom;
073:
074: /**
075: * The left border's size.
076: */
077: private short borderStrokeLeft;
078:
079: /**
080: * The right border's size.
081: */
082: private short borderStrokeRight;
083:
084: /**
085: * The top border's color.
086: */
087: private short colorTop;
088:
089: /**
090: * The left border's color.
091: */
092: private short colorLeft;
093:
094: /**
095: * The bottom border's color.
096: */
097: private short colorBottom;
098:
099: /**
100: * The right border's color.
101: */
102: private short colorRight;
103:
104: /**
105: * A flag indicating whether to enable excels word wrapping.
106: */
107: private boolean wrapText;
108:
109: /**
110: * the horizontal text alignment.
111: */
112: private short horizontalAlignment;
113:
114: /**
115: * the vertical text alignment.
116: */
117: private short verticalAlignment;
118:
119: /**
120: * the font definition for the cell.
121: */
122: private short font;
123:
124: /**
125: * the data style.
126: */
127: private short dataStyle;
128:
129: /**
130: * @param background can be null
131: * @param content can be null
132: */
133: protected HSSFCellStyleKey(
134: final TableCellDefinition background,
135: final RenderBox content,
136: final HSSFDataFormat dataFormat,
137: final ExcelFontFactory fontFactory) {
138: if (background != null) {
139: if (background.getBackgroundColor() != null) {
140: this .color = ExcelColorSupport
141: .getNearestColor(background
142: .getBackgroundColor());
143: }
144: final BorderEdge bottom = background.getBottom();
145: this .colorBottom = ExcelColorSupport
146: .getNearestColor(bottom.getColor());
147: this .borderStrokeBottom = HSSFCellStyleProducer
148: .translateStroke(bottom.getBorderStyle(),
149: bottom.getWidth());
150:
151: final BorderEdge left = background.getLeft();
152: this .colorLeft = ExcelColorSupport.getNearestColor(left
153: .getColor());
154: this .borderStrokeLeft = HSSFCellStyleProducer
155: .translateStroke(left.getBorderStyle(), left
156: .getWidth());
157:
158: final BorderEdge top = background.getTop();
159: this .colorTop = ExcelColorSupport.getNearestColor(top
160: .getColor());
161: this .borderStrokeTop = HSSFCellStyleProducer
162: .translateStroke(top.getBorderStyle(), top
163: .getWidth());
164:
165: final BorderEdge right = background.getRight();
166: this .colorRight = ExcelColorSupport
167: .getNearestColor(right.getColor());
168: this .borderStrokeRight = HSSFCellStyleProducer
169: .translateStroke(right.getBorderStyle(), right
170: .getWidth());
171: }
172:
173: if (content != null) {
174: final StyleSheet styleSheet = content.getStyleSheet();
175: final Color textColor = (Color) styleSheet
176: .getStyleProperty(ElementStyleKeys.PAINT);
177: final String fontName = (String) styleSheet
178: .getStyleProperty(TextStyleKeys.FONT);
179: final short fontSize = (short) styleSheet
180: .getIntStyleProperty(TextStyleKeys.FONTSIZE, 0);
181: final boolean bold = styleSheet
182: .getBooleanStyleProperty(TextStyleKeys.BOLD);
183: final boolean italic = styleSheet
184: .getBooleanStyleProperty(TextStyleKeys.ITALIC);
185: final boolean underline = styleSheet
186: .getBooleanStyleProperty(TextStyleKeys.UNDERLINED);
187: final boolean strikethrough = styleSheet
188: .getBooleanStyleProperty(TextStyleKeys.STRIKETHROUGH);
189: final HSSFFontWrapper wrapper = new HSSFFontWrapper(
190: fontName, fontSize, bold, italic, underline,
191: strikethrough, textColor);
192: final HSSFFont excelFont = fontFactory
193: .getExcelFont(wrapper);
194: this .font = excelFont.getIndex();
195:
196: final ElementAlignment horizontal = (ElementAlignment) styleSheet
197: .getStyleProperty(ElementStyleKeys.ALIGNMENT);
198: this .horizontalAlignment = HSSFCellStyleProducer
199: .convertAlignment(horizontal);
200: final ElementAlignment vertical = (ElementAlignment) styleSheet
201: .getStyleProperty(ElementStyleKeys.VALIGNMENT);
202: this .verticalAlignment = HSSFCellStyleProducer
203: .convertAlignment(vertical);
204: final String dataStyle = (String) styleSheet
205: .getStyleProperty(ElementStyleKeys.EXCEL_DATA_FORMAT_STRING);
206: if (dataStyle != null) {
207: this .dataStyle = dataFormat.getFormat(dataStyle);
208: }
209: this .wrapText = isWrapText(styleSheet);
210: }
211: }
212:
213: private boolean isWrapText(final StyleSheet styleSheet) {
214: final Object excelWrap = styleSheet
215: .getStyleProperty(ElementStyleKeys.EXCEL_WRAP_TEXT);
216: if (excelWrap != null) {
217: return Boolean.TRUE.equals(excelWrap);
218: }
219: return TextWrap.WRAP.equals(styleSheet.getStyleProperty(
220: TextStyleKeys.TEXT_WRAP, TextWrap.WRAP));
221: }
222:
223: protected HSSFCellStyleKey(final HSSFCellStyle style) {
224:
225: this .color = style.getFillForegroundColor();
226: this .colorTop = style.getTopBorderColor();
227: this .colorLeft = style.getLeftBorderColor();
228: this .colorBottom = style.getBottomBorderColor();
229: this .colorRight = style.getRightBorderColor();
230: this .borderStrokeTop = style.getBorderTop();
231: this .borderStrokeLeft = style.getBorderLeft();
232: this .borderStrokeBottom = style.getBorderBottom();
233: this .borderStrokeRight = style.getBorderRight();
234:
235: this .dataStyle = style.getDataFormat();
236: this .font = style.getFontIndex();
237: this .horizontalAlignment = style.getAlignment();
238: this .verticalAlignment = style.getVerticalAlignment();
239: this .wrapText = style.getWrapText();
240: }
241:
242: public boolean equals(final Object o) {
243: if (this == o) {
244: return true;
245: }
246: if (o == null || getClass() != o.getClass()) {
247: return false;
248: }
249:
250: final HSSFCellStyleKey that = (HSSFCellStyleKey) o;
251:
252: if (borderStrokeBottom != that.borderStrokeBottom) {
253: return false;
254: }
255: if (borderStrokeLeft != that.borderStrokeLeft) {
256: return false;
257: }
258: if (borderStrokeRight != that.borderStrokeRight) {
259: return false;
260: }
261: if (borderStrokeTop != that.borderStrokeTop) {
262: return false;
263: }
264: if (color != that.color) {
265: return false;
266: }
267: if (colorBottom != that.colorBottom) {
268: return false;
269: }
270: if (colorLeft != that.colorLeft) {
271: return false;
272: }
273: if (colorRight != that.colorRight) {
274: return false;
275: }
276: if (colorTop != that.colorTop) {
277: return false;
278: }
279: if (dataStyle != that.dataStyle) {
280: return false;
281: }
282: if (font != that.font) {
283: return false;
284: }
285: if (horizontalAlignment != that.horizontalAlignment) {
286: return false;
287: }
288: if (verticalAlignment != that.verticalAlignment) {
289: return false;
290: }
291: if (wrapText != that.wrapText) {
292: return false;
293: }
294:
295: return true;
296: }
297:
298: public int hashCode() {
299: int result = (int) color;
300: result = 29 * result + (int) borderStrokeTop;
301: result = 29 * result + (int) borderStrokeBottom;
302: result = 29 * result + (int) borderStrokeLeft;
303: result = 29 * result + (int) borderStrokeRight;
304: result = 29 * result + (int) colorTop;
305: result = 29 * result + (int) colorLeft;
306: result = 29 * result + (int) colorBottom;
307: result = 29 * result + (int) colorRight;
308: result = 29 * result + (wrapText ? 1 : 0);
309: result = 29 * result + (int) horizontalAlignment;
310: result = 29 * result + (int) verticalAlignment;
311: result = 29 * result + (int) font;
312: result = 29 * result + (int) dataStyle;
313: return result;
314: }
315:
316: public short getColor() {
317: return color;
318: }
319:
320: public short getBorderStrokeTop() {
321: return borderStrokeTop;
322: }
323:
324: public short getBorderStrokeBottom() {
325: return borderStrokeBottom;
326: }
327:
328: public short getBorderStrokeLeft() {
329: return borderStrokeLeft;
330: }
331:
332: public short getBorderStrokeRight() {
333: return borderStrokeRight;
334: }
335:
336: public short getColorTop() {
337: return colorTop;
338: }
339:
340: public short getColorLeft() {
341: return colorLeft;
342: }
343:
344: public short getColorBottom() {
345: return colorBottom;
346: }
347:
348: public short getColorRight() {
349: return colorRight;
350: }
351:
352: public boolean isWrapText() {
353: return wrapText;
354: }
355:
356: public short getHorizontalAlignment() {
357: return horizontalAlignment;
358: }
359:
360: public short getVerticalAlignment() {
361: return verticalAlignment;
362: }
363:
364: public short getFont() {
365: return font;
366: }
367:
368: public short getDataStyle() {
369: return dataStyle;
370: }
371: }
372:
373: /**
374: * The workbook wide singleton instance of an empty cell.
375: */
376: private HSSFCellStyle emptyCellStyle;
377:
378: /**
379: * the font factory is used to create excel fonts.
380: */
381: private ExcelFontFactory fontFactory;
382:
383: /**
384: * The workbook, which creates all cells and styles.
385: */
386: private HSSFWorkbook workbook;
387:
388: /**
389: * The data format is used to create format strings.
390: */
391: private HSSFDataFormat dataFormat;
392:
393: /**
394: * White background. This is the default background if not specified
395: * otherwise.
396: */
397: private static final short WHITE_INDEX = (new HSSFColor.WHITE())
398: .getIndex();
399:
400: /**
401: * The cache for all generated styles.
402: */
403: private HashMap styleCache;
404:
405: private boolean warningDone;
406: private boolean hardLimit;
407:
408: /**
409: * The class does the dirty work of creating the HSSF-objects.
410: *
411: * @param workbook the workbook for which the styles should be created.
412: */
413: public HSSFCellStyleProducer(final HSSFWorkbook workbook,
414: final boolean hardLimit) {
415: if (workbook == null) {
416: throw new NullPointerException();
417: }
418: this .styleCache = new HashMap();
419: this .workbook = workbook;
420: this .fontFactory = new ExcelFontFactory(workbook);
421: this .dataFormat = workbook.createDataFormat();
422: this .hardLimit = hardLimit;
423:
424: // Read in the styles ...
425: final short predefinedStyles = workbook.getNumCellStyles();
426: for (short i = 0; i < predefinedStyles; i++) {
427: final HSSFCellStyle cellStyleAt = workbook
428: .getCellStyleAt(i);
429: this .styleCache.put(new HSSFCellStyleKey(cellStyleAt),
430: cellStyleAt);
431: }
432: }
433:
434: /**
435: * Gets the default style, which is used for empty cells.
436: *
437: * @return the default style for empty cells.
438: */
439: public HSSFCellStyle getEmptyCellStyle() {
440: if (emptyCellStyle == null) {
441: emptyCellStyle = workbook.createCellStyle();
442: emptyCellStyle
443: .setFillForegroundColor(HSSFCellStyleProducer.WHITE_INDEX);
444: emptyCellStyle
445: .setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
446: }
447: return emptyCellStyle;
448: }
449:
450: /**
451: * Creates a HSSFCellStyle based on the given ExcelDataCellStyle. If a
452: * similiar cell style was previously generated, then reuse that cached
453: * result.
454: *
455: * @param element never null
456: * @param bg the background style for the table cell.
457: * @return the generated or cached HSSFCellStyle.
458: */
459: public HSSFCellStyle createCellStyle(final RenderBox element,
460: final TableCellDefinition bg) {
461: // check, whether that style is already created
462: final HSSFCellStyleKey styleKey = new HSSFCellStyleKey(bg,
463: element, dataFormat, fontFactory);
464: if (styleCache.containsKey(styleKey)) {
465: return (HSSFCellStyle) styleCache.get(styleKey);
466: }
467:
468: if ((styleCache.size()) > 4000) {
469: if (warningDone == false) {
470: Log
471: .warn("HSSFCellStyleProducer has reached the limit of 4000 created styles.");
472: warningDone = true;
473: }
474: if (hardLimit) {
475: Log
476: .warn("HSSFCellStyleProducer will not create more styles. New cells will not have any style.");
477: return null;
478: }
479: }
480: final HSSFCellStyle hssfCellStyle = workbook.createCellStyle();
481: if (element != null) {
482: hssfCellStyle.setAlignment(styleKey
483: .getHorizontalAlignment());
484: hssfCellStyle.setVerticalAlignment(styleKey
485: .getVerticalAlignment());
486: hssfCellStyle.setFont(workbook
487: .getFontAt(styleKey.getFont()));
488: hssfCellStyle.setWrapText(styleKey.isWrapText());
489: hssfCellStyle.setDataFormat(styleKey.getDataStyle());
490: }
491: if (bg != null) {
492: if (BorderStyle.NONE
493: .equals(bg.getBottom().getBorderStyle()) == false) {
494: hssfCellStyle.setBorderBottom(styleKey
495: .getBorderStrokeBottom());
496: hssfCellStyle.setBottomBorderColor(styleKey
497: .getColorBottom());
498: }
499: if (BorderStyle.NONE.equals(bg.getTop().getBorderStyle()) == false) {
500: hssfCellStyle.setBorderTop(styleKey
501: .getBorderStrokeTop());
502: hssfCellStyle.setTopBorderColor(styleKey.getColorTop());
503: }
504: if (BorderStyle.NONE.equals(bg.getLeft().getBorderStyle()) == false) {
505: hssfCellStyle.setBorderLeft(styleKey
506: .getBorderStrokeLeft());
507: hssfCellStyle.setLeftBorderColor(styleKey
508: .getColorLeft());
509: }
510: if (BorderStyle.NONE.equals(bg.getRight().getBorderStyle()) == false) {
511: hssfCellStyle.setBorderRight(styleKey
512: .getBorderStrokeRight());
513: hssfCellStyle.setRightBorderColor(styleKey
514: .getColorRight());
515: }
516: if (bg.getBackgroundColor() != null) {
517: hssfCellStyle.setFillForegroundColor(styleKey
518: .getColor());
519: hssfCellStyle
520: .setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
521: }
522: }
523:
524: styleCache.put(styleKey, hssfCellStyle);
525: return hssfCellStyle;
526: }
527:
528: /**
529: * Converts the given element alignment into one of the
530: * HSSFCellStyle-constants.
531: *
532: * @param e the JFreeReport element alignment.
533: * @return the HSSFCellStyle-Alignment.
534: * @throws IllegalArgumentException if an Unknown JFreeReport alignment is
535: * given.
536: */
537: protected static short convertAlignment(final ElementAlignment e) {
538: if (e == ElementAlignment.LEFT) {
539: return HSSFCellStyle.ALIGN_LEFT;
540: }
541: if (e == ElementAlignment.RIGHT) {
542: return HSSFCellStyle.ALIGN_RIGHT;
543: }
544: if (e == ElementAlignment.CENTER) {
545: return HSSFCellStyle.ALIGN_CENTER;
546: }
547: if (e == ElementAlignment.TOP) {
548: return HSSFCellStyle.VERTICAL_TOP;
549: }
550: if (e == ElementAlignment.BOTTOM) {
551: return HSSFCellStyle.VERTICAL_BOTTOM;
552: }
553: if (e == ElementAlignment.MIDDLE) {
554: return HSSFCellStyle.VERTICAL_CENTER;
555: }
556:
557: throw new IllegalArgumentException("Invalid alignment");
558: }
559:
560: /**
561: * Tries to translate the given stroke width into one of the predefined excel
562: * border styles.
563: *
564: * @param widthRaw the AWT-Stroke-Width.
565: * @return the translated excel border width.
566: */
567: protected static short translateStroke(
568: final BorderStyle borderStyle, final long widthRaw) {
569: final double width = StrictGeomUtility
570: .toExternalValue(widthRaw);
571: if (BorderStyle.NONE.equals(borderStyle)) {
572: return HSSFCellStyle.BORDER_NONE;
573: }
574: if (BorderStyle.DASHED.equals(borderStyle)) {
575: if (width <= 1.5) {
576: return HSSFCellStyle.BORDER_DASHED;
577: } else {
578: return HSSFCellStyle.BORDER_MEDIUM_DASHED;
579: }
580: }
581: if (BorderStyle.DOT_DOT_DASH.equals(borderStyle)) {
582: if (width <= 1.5) {
583: return HSSFCellStyle.BORDER_DASH_DOT_DOT;
584: } else {
585: return HSSFCellStyle.BORDER_MEDIUM_DASH_DOT_DOT;
586: }
587: }
588: if (BorderStyle.DOT_DASH.equals(borderStyle)) {
589: if (width <= 1.5) {
590: return HSSFCellStyle.BORDER_DASH_DOT;
591: } else {
592: return HSSFCellStyle.BORDER_MEDIUM_DASH_DOT;
593: }
594: }
595: if (BorderStyle.DOTTED.equals(borderStyle)) {
596: return HSSFCellStyle.BORDER_DOTTED;
597: }
598: if (BorderStyle.DOUBLE.equals(borderStyle)) {
599: return HSSFCellStyle.BORDER_DOUBLE;
600: }
601:
602: if (width == 0) {
603: return HSSFCellStyle.BORDER_NONE;
604: } else if (width <= 0.5) {
605: return HSSFCellStyle.BORDER_HAIR;
606: } else if (width <= 1) {
607: return HSSFCellStyle.BORDER_THIN;
608: } else if (width <= 1.5) {
609: return HSSFCellStyle.BORDER_MEDIUM;
610: }
611: // else if (width <= 2)
612: // {
613: // return HSSFCellStyle.BORDER_DOUBLE;
614: // }
615: else {
616: return HSSFCellStyle.BORDER_THICK;
617: }
618: }
619:
620: public ExcelFontFactory getFontFactory() {
621: return fontFactory;
622: }
623: }
|