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: package net.sf.jasperreports.engine.fill;
029:
030: import java.awt.Color;
031: import java.util.HashMap;
032: import java.util.Iterator;
033: import java.util.List;
034: import java.util.Map;
035:
036: import net.sf.jasperreports.crosstabs.JRCellContents;
037: import net.sf.jasperreports.engine.JRBox;
038: import net.sf.jasperreports.engine.JRDefaultStyleProvider;
039: import net.sf.jasperreports.engine.JRElement;
040: import net.sf.jasperreports.engine.JRException;
041: import net.sf.jasperreports.engine.JRFrame;
042: import net.sf.jasperreports.engine.JRGraphicElement;
043: import net.sf.jasperreports.engine.JRPrintElement;
044: import net.sf.jasperreports.engine.JRPrintFrame;
045: import net.sf.jasperreports.engine.JRStyle;
046: import net.sf.jasperreports.engine.JRStyleSetter;
047: import net.sf.jasperreports.engine.base.JRBaseBox;
048:
049: import org.apache.commons.collections.ReferenceMap;
050:
051: /**
052: * Crosstab cell contents filler.
053: *
054: * @author Lucian Chirita (lucianc@users.sourceforge.net)
055: * @version $Id: JRFillCellContents.java 1808 2007-08-08 13:08:59Z lucianc $
056: */
057: public class JRFillCellContents extends JRFillElementContainer
058: implements JRCellContents, JRCloneable, JRStyleSetter {
059: private final Map transformedContentsCache;
060: private final Map boxContentsCache;
061: private final JRClonePool clonePool;
062:
063: private JRFillCellContents original;
064:
065: private final JRCellContents parentCell;
066:
067: private JRBox box;
068:
069: private int height;
070: private int width;
071:
072: private int x;
073: private int y;
074: private int verticalSpan;
075: private byte verticalPositionType = JRCellContents.POSITION_Y_TOP;
076:
077: private Map templateFrames;
078:
079: private JRDefaultStyleProvider defaultStyleProvider;
080: private JRStyle initStyle;
081:
082: public JRFillCellContents(JRBaseFiller filler, JRCellContents cell,
083: JRFillObjectFactory factory) {
084: super (filler, cell, factory);
085:
086: defaultStyleProvider = factory.getDefaultStyleProvider();
087:
088: parentCell = cell;
089:
090: box = cell.getBox();
091:
092: width = cell.getWidth();
093: height = cell.getHeight();
094:
095: factory.registerDelayedStyleSetter(this , parentCell);
096:
097: initElements();
098:
099: initConditionalStyles();
100:
101: initTemplatesMap();
102:
103: transformedContentsCache = new ReferenceMap();
104: boxContentsCache = new HashMap();
105: clonePool = new JRClonePool(this , true, true);
106: }
107:
108: private void initTemplatesMap() {
109: templateFrames = new HashMap();
110: }
111:
112: protected JRFillCellContents(JRFillCellContents cellContents,
113: JRFillCloneFactory factory) {
114: super (cellContents, factory);
115:
116: defaultStyleProvider = cellContents.defaultStyleProvider;
117:
118: parentCell = cellContents.parentCell;
119:
120: box = cellContents.box;
121:
122: width = cellContents.width;
123: height = cellContents.height;
124:
125: initStyle = cellContents.initStyle;
126:
127: initElements();
128:
129: initConditionalStyles();
130:
131: this .templateFrames = cellContents.templateFrames;
132:
133: transformedContentsCache = new ReferenceMap();
134: boxContentsCache = new HashMap();
135: clonePool = new JRClonePool(this , true, true);
136:
137: verticalPositionType = cellContents.verticalPositionType;
138: }
139:
140: public Color getBackcolor() {
141: return parentCell.getBackcolor();
142: }
143:
144: public JRBox getBox() {
145: return box;
146: }
147:
148: protected void setBox(JRBox box) {
149: this .box = box;
150:
151: initTemplatesMap();
152: }
153:
154: public int getHeight() {
155: return height;
156: }
157:
158: public int getWidth() {
159: return width;
160: }
161:
162: protected void setHeight(int height) {
163: this .height = height;
164: }
165:
166: protected void setWidth(int width) {
167: this .width = width;
168: }
169:
170: public JRFillCellContents getBoxContents(boolean left,
171: boolean right, boolean top) {
172: if (box == null) {
173: return this ;
174: }
175:
176: boolean copyLeft = left
177: && box.getLeftBorder() == JRGraphicElement.PEN_NONE
178: && box.getRightBorder() != JRGraphicElement.PEN_NONE;
179: boolean copyRight = right
180: && box.getRightBorder() == JRGraphicElement.PEN_NONE
181: && box.getLeftBorder() != JRGraphicElement.PEN_NONE;
182: boolean copyTop = top
183: && box.getTopBorder() == JRGraphicElement.PEN_NONE
184: && box.getBottomBorder() != JRGraphicElement.PEN_NONE;
185:
186: if (!(copyLeft || copyRight || copyTop)) {
187: return this ;
188: }
189:
190: Object key = new BoxContents(copyLeft, copyRight, copyTop);
191: JRFillCellContents boxContents = (JRFillCellContents) boxContentsCache
192: .get(key);
193: if (boxContents == null) {
194: boxContents = (JRFillCellContents) createClone();
195:
196: JRBaseBox newBox = new JRBaseBox(box);
197:
198: if (copyLeft) {
199: newBox.setLeftBorder(box.getRightBorder());
200: newBox.setLeftBorderColor(box.getRightBorderColor());
201: }
202:
203: if (copyRight) {
204: newBox.setRightBorder(box.getLeftBorder());
205: newBox.setRightBorderColor(box.getLeftBorderColor());
206: }
207:
208: if (copyTop) {
209: newBox.setTopBorder(box.getBottomBorder());
210: newBox.setTopBorderColor(box.getBottomBorderColor());
211: }
212:
213: boxContents.setBox(newBox);
214:
215: boxContentsCache.put(key, boxContents);
216: }
217:
218: return boxContents;
219: }
220:
221: public JRFillCellContents getTransformedContents(int newWidth,
222: int newHeight, byte xPosition, byte yPosition)
223: throws JRException {
224: if ((getHeight() == newHeight) && (getWidth() == newWidth)) {
225: return this ;
226: }
227:
228: if (newHeight < getHeight() || newWidth < getWidth()) {
229: throw new JRException("Cannot shrink cell contents.");
230: }
231:
232: Object key = new StretchedContents(newWidth, newHeight,
233: xPosition, yPosition);
234:
235: JRFillCellContents transformedCell = (JRFillCellContents) transformedContentsCache
236: .get(key);
237: if (transformedCell == null) {
238: transformedCell = (JRFillCellContents) createClone();
239: transformedCell.transform(newWidth, newHeight, xPosition,
240: yPosition);
241: transformedCell.setElementsBandBottomY();
242:
243: transformedContentsCache.put(key, transformedCell);
244: }
245:
246: return transformedCell;
247: }
248:
249: private void transform(int newWidth, int newHeight, byte xPosition,
250: byte yPosition) {
251: transformElements(newWidth, newHeight, xPosition, yPosition);
252:
253: width = newWidth;
254: height = newHeight;
255: }
256:
257: private void transformElements(int newWidth, int newHeight,
258: byte xPosition, byte yPosition) {
259: if ((height == newHeight || yPosition == JRCellContents.POSITION_Y_TOP)
260: && (width == newWidth || xPosition == JRCellContents.POSITION_X_LEFT)) {
261: return;
262: }
263:
264: double scaleX = -1d;
265: int offsetX = 0;
266: switch (xPosition) {
267: case JRCellContents.POSITION_X_CENTER:
268: offsetX = (newWidth - width) / 2;
269: break;
270: case JRCellContents.POSITION_X_RIGHT:
271: offsetX = newWidth - width;
272: break;
273: case JRCellContents.POSITION_X_STRETCH:
274: scaleX = ((double) newWidth) / width;
275: break;
276: }
277:
278: double scaleY = -1d;
279: int offsetY = 0;
280: switch (yPosition) {
281: case JRCellContents.POSITION_Y_MIDDLE:
282: offsetY = (newHeight - height) / 2;
283: break;
284: case JRCellContents.POSITION_Y_BOTTOM:
285: offsetY = newHeight - height;
286: break;
287: case JRCellContents.POSITION_X_STRETCH:
288: scaleY = ((double) newHeight) / height;
289: break;
290: }
291:
292: transformElements(getElements(), scaleX, offsetX, scaleY,
293: offsetY);
294: }
295:
296: private static void transformElements(JRElement[] elements,
297: double scaleX, int offsetX, double scaleY, int offsetY) {
298: if (elements != null) {
299: for (int i = 0; i < elements.length; i++) {
300: JRFillElement element = (JRFillElement) elements[i];
301:
302: if (scaleX != -1d) {
303: element.setX((int) (element.getX() * scaleX));
304: element
305: .setWidth((int) (element.getWidth() * scaleX));
306: }
307:
308: if (offsetX != 0) {
309: element.setX(element.getX() + offsetX);
310: }
311:
312: if (scaleY != -1d) {
313: element.setY((int) (element.getY() * scaleY));
314: element
315: .setHeight((int) (element.getHeight() * scaleY));
316: }
317:
318: if (offsetY != 0) {
319: element.setY(element.getY() + offsetY);
320: }
321:
322: if (element instanceof JRFrame) {
323: JRElement[] frameElements = ((JRFrame) element)
324: .getElements();
325: transformElements(frameElements, scaleX, offsetX,
326: scaleY, offsetY);
327: }
328: }
329: }
330: }
331:
332: protected void prepare(int availableStretchHeight)
333: throws JRException {
334: initFill();
335: resetElements();
336: prepareElements(availableStretchHeight, true);
337: }
338:
339: protected JRPrintFrame fill() throws JRException {
340: stretchElements();
341: moveBandBottomElements();
342: removeBlankElements();
343:
344: JRTemplatePrintFrame printCell = new JRTemplatePrintFrame(
345: getTemplateFrame());
346: printCell.setX(x);
347: printCell.setY(y);
348: printCell.setWidth(width);
349:
350: fillElements(printCell);
351:
352: verticallyPositionElements(printCell);
353:
354: printCell.setHeight(getPrintHeight());
355:
356: return printCell;
357: }
358:
359: private JRTemplateFrame getTemplateFrame() {
360: JRStyle style = getStyle();
361: JRTemplateFrame template = (JRTemplateFrame) templateFrames
362: .get(style);
363: if (template == null) {
364: template = new JRTemplateFrame(filler.getJasperPrint()
365: .getDefaultStyleProvider(), this );
366: templateFrames.put(style, template);
367: }
368: return template;
369: }
370:
371: protected void verticallyPositionElements(
372: JRTemplatePrintFrame printCell) {
373: int positionOffset;
374:
375: switch (verticalPositionType) {
376: case JRCellContents.POSITION_Y_MIDDLE:
377: positionOffset = (getStretchHeight() - getContainerHeight()) / 2;
378: break;
379: case JRCellContents.POSITION_Y_BOTTOM:
380: positionOffset = getStretchHeight() - getContainerHeight();
381: break;
382: default:
383: positionOffset = 0;
384: break;
385: }
386:
387: if (positionOffset != 0) {
388: List printElements = printCell.getElements();
389:
390: int positionY = getStretchHeight() - positionOffset;
391: boolean outside = false;
392: for (Iterator it = printElements.iterator(); !outside
393: && it.hasNext();) {
394: JRPrintElement element = (JRPrintElement) it.next();
395: outside = element.getY() > positionY;
396: }
397:
398: if (!outside) {
399: for (Iterator it = printElements.iterator(); it
400: .hasNext();) {
401: JRPrintElement element = (JRPrintElement) it.next();
402: element.setY(element.getY() + positionOffset);
403: }
404: }
405: }
406: }
407:
408: protected int getPrintHeight() {
409: return getStretchHeight() + getTopPadding()
410: + getBottomPadding();
411: }
412:
413: protected void stretchTo(int stretchHeight) {
414: setStretchHeight(stretchHeight - getTopPadding()
415: - getBottomPadding());
416: }
417:
418: protected static class BoxContents {
419: final boolean left;
420: final boolean right;
421: final boolean top;
422: final int hashCode;
423:
424: public BoxContents(boolean left, boolean right, boolean top) {
425: this .left = left;
426: this .right = right;
427: this .top = top;
428:
429: int hash = left ? 1231 : 1237;
430: hash = 31 * hash + (right ? 1231 : 1237);
431: hash = 31 * hash + (top ? 1231 : 1237);
432: hashCode = hash;
433: }
434:
435: public boolean equals(Object obj) {
436: if (obj == this ) {
437: return true;
438: }
439:
440: BoxContents b = (BoxContents) obj;
441:
442: return b.left == left && b.right == right && b.top == top;
443: }
444:
445: public int hashCode() {
446: return hashCode;
447: }
448: }
449:
450: protected static class StretchedContents {
451: final int newHeight;
452: final int newWidth;
453: final int hashCode;
454: final byte xPosition;
455: final byte yPosition;
456:
457: StretchedContents(int newWidth, int newHeight, byte xPosition,
458: byte yPosition) {
459: this .newHeight = newHeight;
460: this .newWidth = newWidth;
461: this .xPosition = xPosition;
462: this .yPosition = yPosition;
463:
464: int hash = newHeight;
465: hash = 31 * hash + newWidth;
466: hash = 31 * hash + xPosition;
467: hash = 31 * hash + yPosition;
468: hashCode = hash;
469: }
470:
471: public boolean equals(Object o) {
472: if (o == this ) {
473: return true;
474: }
475:
476: StretchedContents s = (StretchedContents) o;
477:
478: return s.newHeight == newHeight && s.newWidth == newWidth
479: && s.xPosition == xPosition
480: && s.yPosition == yPosition;
481: }
482:
483: public int hashCode() {
484: return hashCode;
485: }
486: }
487:
488: protected int getContainerHeight() {
489: return getHeight() - getTopPadding() - getBottomPadding();
490: }
491:
492: protected int getTopPadding() {
493: return box == null ? 0 : box.getTopPadding();
494: }
495:
496: protected int getBottomPadding() {
497: return box == null ? 0 : box.getBottomPadding();
498: }
499:
500: public JRCloneable createClone() {
501: JRFillCloneFactory factory = new JRFillCloneFactory();
502: return createClone(factory);
503: }
504:
505: public JRCloneable createClone(JRFillCloneFactory factory) {
506: return new JRFillCellContents(this , factory);
507: }
508:
509: public JRFillCellContents getWorkingClone() {
510: JRFillCellContents clone = (JRFillCellContents) clonePool
511: .getClone();
512: clone.original = this ;
513: return clone;
514: }
515:
516: public void releaseWorkingClone() {
517: original.clonePool.releaseClone(this );
518: }
519:
520: public void setX(int x) {
521: this .x = x;
522: }
523:
524: public void setY(int y) {
525: this .y = y;
526: }
527:
528: public int getVerticalSpan() {
529: return verticalSpan;
530: }
531:
532: public void setVerticalSpan(int span) {
533: verticalSpan = span;
534: }
535:
536: public void setVerticalPositionType(byte positionType) {
537: this .verticalPositionType = positionType;
538: }
539:
540: protected void evaluate(byte evaluation) throws JRException {
541: evaluateConditionalStyles(evaluation);
542: super .evaluate(evaluation);
543: }
544:
545: public JRDefaultStyleProvider getDefaultStyleProvider() {
546: return defaultStyleProvider;
547: }
548:
549: public JRStyle getStyle() {
550: JRStyle crtStyle = initStyle;
551:
552: boolean isUsingDefaultStyle = false;
553:
554: if (crtStyle == null) {
555: crtStyle = filler.getDefaultStyle();
556: isUsingDefaultStyle = true;
557: }
558:
559: JRStyle evalStyle = getEvaluatedConditionalStyle(crtStyle);
560:
561: if (isUsingDefaultStyle && evalStyle == crtStyle)
562: evalStyle = null;
563:
564: return evalStyle;
565: }
566:
567: protected void initConditionalStyles() {
568: super .initConditionalStyles();
569: collectConditionalStyle(initStyle);
570: }
571:
572: public Byte getMode() {
573: return parentCell.getMode();
574: }
575:
576: public String getStyleNameReference() {
577: return null;
578: }
579:
580: public void setStyle(JRStyle style) {
581: this .initStyle = style;
582: collectConditionalStyle(style);
583: }
584:
585: public void setStyleNameReference(String name) {
586: throw new UnsupportedOperationException(
587: "Style name references not allowed at fill time");
588: }
589:
590: }
|