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: * RenderableReplacedContent.java
027: * ------------
028: * (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
029: */package org.jfree.report.layout.model;
030:
031: import java.awt.Dimension;
032: import java.awt.Shape;
033: import java.awt.geom.Rectangle2D;
034:
035: import org.jfree.report.ImageContainer;
036: import org.jfree.report.layout.output.OutputProcessorFeature;
037: import org.jfree.report.layout.output.OutputProcessorMetaData;
038: import org.jfree.report.style.ElementStyleKeys;
039: import org.jfree.report.style.StyleSheet;
040: import org.jfree.report.util.geom.StrictGeomUtility;
041: import org.jfree.resourceloader.ResourceKey;
042: import org.jfree.ui.ExtendedDrawable;
043:
044: /**
045: * Creation-Date: 03.04.2007, 15:10:19
046: *
047: * @author Thomas Morgner
048: */
049: public class RenderableReplacedContent extends RenderNode {
050: private transient Object contentCached;
051: private Object content;
052: private ResourceKey source;
053: private boolean imageResolutionMapping;
054: private boolean avoidPagebreaksInside;
055: private long contentWidth;
056: private long contentHeight;
057:
058: private RenderLength requestedWidth;
059: private RenderLength requestedHeight;
060: private RenderLength minimumWidth;
061: private RenderLength minimumHeight;
062: private RenderLength maximumWidth;
063: private RenderLength maximumHeight;
064:
065: public RenderableReplacedContent(final StyleSheet styleSheet,
066: final Object content, final ResourceKey source,
067: final OutputProcessorMetaData metaData) {
068: super (styleSheet);
069: this .content = content;
070: this .source = source;
071: this .avoidPagebreaksInside = styleSheet
072: .getBooleanStyleProperty(ElementStyleKeys.AVOID_PAGEBREAK_INSIDE);
073: setMajorAxis(VERTICAL_AXIS);
074: setMinorAxis(HORIZONTAL_AXIS);
075:
076: minimumWidth = RenderLength.createFromRaw(styleSheet
077: .getDoubleStyleProperty(ElementStyleKeys.MIN_WIDTH, 0));
078: minimumHeight = RenderLength
079: .createFromRaw(styleSheet.getDoubleStyleProperty(
080: ElementStyleKeys.MIN_HEIGHT, 0));
081: maximumWidth = RenderLength.createFromRaw(styleSheet
082: .getDoubleStyleProperty(ElementStyleKeys.MAX_WIDTH,
083: Short.MAX_VALUE));
084: maximumHeight = RenderLength.createFromRaw(styleSheet
085: .getDoubleStyleProperty(ElementStyleKeys.MAX_HEIGHT,
086: Short.MAX_VALUE));
087:
088: final Float prefWidth = (Float) styleSheet.getStyleProperty(
089: ElementStyleKeys.WIDTH, null);
090: if (prefWidth != null) {
091: requestedWidth = RenderLength.createFromRaw(prefWidth
092: .doubleValue());
093: } else {
094: requestedWidth = RenderLength.AUTO;
095: }
096:
097: final Float prefHeight = (Float) styleSheet.getStyleProperty(
098: ElementStyleKeys.HEIGHT, null);
099: if (prefHeight != null) {
100: requestedHeight = RenderLength.createFromRaw(prefHeight
101: .doubleValue());
102: } else {
103: requestedHeight = RenderLength.AUTO;
104: }
105:
106: if (content instanceof ImageContainer) {
107: this .imageResolutionMapping = metaData
108: .isFeatureSupported(OutputProcessorFeature.IMAGE_RESOLUTION_MAPPING);
109: final double displayResolution = metaData
110: .getNumericFeatureValue(OutputProcessorFeature.DEVICE_RESOLUTION);
111: final double correctionFactorPxToPoint = 72.0 / displayResolution;
112:
113: final ImageContainer ir = (ImageContainer) content;
114: final double scaleX = ir.getScaleX();
115: final double scaleY = ir.getScaleY();
116: if (imageResolutionMapping) {
117: contentWidth = StrictGeomUtility.toInternalValue(ir
118: .getImageWidth()
119: * scaleX * correctionFactorPxToPoint);
120: contentHeight = StrictGeomUtility.toInternalValue(ir
121: .getImageHeight()
122: * scaleY * correctionFactorPxToPoint);
123: } else {
124: contentWidth = StrictGeomUtility.toInternalValue(ir
125: .getImageWidth()
126: * scaleX);
127: contentHeight = StrictGeomUtility.toInternalValue(ir
128: .getImageHeight()
129: * scaleY);
130: }
131: } else if (content instanceof ExtendedDrawable) {
132: final ExtendedDrawable edr = (ExtendedDrawable) content;
133: final Dimension preferredSize = edr.getPreferredSize();
134: contentWidth = StrictGeomUtility
135: .toInternalValue(preferredSize.getWidth());
136: contentHeight = StrictGeomUtility
137: .toInternalValue(preferredSize.getHeight());
138: } else if (content instanceof Shape) {
139: final Shape s = (Shape) content;
140: final Rectangle2D bounds2D = s.getBounds2D();
141: contentWidth = StrictGeomUtility.toInternalValue(bounds2D
142: .getWidth());
143: contentHeight = StrictGeomUtility.toInternalValue(bounds2D
144: .getHeight());
145: }
146:
147: //Log.debug (this);
148: }
149:
150: public ResourceKey getSource() {
151: return source;
152: }
153:
154: public Object getRawObject() {
155: return content;
156: }
157:
158: public long getContentWidth() {
159: return contentWidth;
160: }
161:
162: public long getContentHeight() {
163: return contentHeight;
164: }
165:
166: public RenderLength getRequestedWidth() {
167: return requestedWidth;
168: }
169:
170: public RenderLength getRequestedHeight() {
171: return requestedHeight;
172: }
173:
174: public boolean isImageResolutionMapping() {
175: return imageResolutionMapping;
176: }
177:
178: public boolean isAvoidPagebreaksInside() {
179: return avoidPagebreaksInside;
180: }
181:
182: public long computeWidth(final long bcw) {
183: final long width = computeWidthInternal(bcw);
184: return computeLength(minimumWidth.resolve(bcw), maximumWidth
185: .resolve(bcw), width);
186: }
187:
188: public long computeHeight(final long bcw, final long computedWidth) {
189: final long height = computeHeightInternal(bcw, computedWidth);
190: return computeLength(minimumHeight.resolve(bcw), maximumHeight
191: .resolve(bcw), height);
192: }
193:
194: private long computeLength(final long min, final long max,
195: final long pref) {
196: if (pref > max) {
197: if (max < min) {
198: return min;
199: }
200: return max;
201: }
202:
203: if (pref < min) {
204: if (max < min) {
205: return max;
206: }
207: return min;
208: }
209:
210: if (max < pref) {
211: return max;
212: }
213: return pref;
214: }
215:
216: private long computeWidthInternal(final long blockContextWidth) {
217: if (RenderLength.AUTO.equals(getRequestedWidth())) {
218: // if width is auto, and height is auto,
219: if (RenderLength.AUTO.equals(getRequestedHeight())) {
220: // use the intrinsic width ..
221: return getContentWidth();
222: }
223: // if height is not auto, but the width is, then compute a width that
224: // preserves the aspect ratio.
225: else if (getContentHeight() > 0) {
226: final long height = getRequestedHeight().resolve(
227: blockContextWidth);
228: return height * getComputedWidth() / getContentHeight();
229: } else {
230: return 0;
231: }
232: } else {
233: // width is not auto.
234: return getRequestedWidth().resolve(blockContextWidth);
235: }
236: }
237:
238: private long computeHeightInternal(final long blockContextWidth,
239: final long computedWidth) {
240: final RenderLength requestedHeight = getRequestedHeight();
241: if (RenderLength.AUTO.equals(getRequestedWidth())) {
242: // if width is auto, and height is auto,
243: if (RenderLength.AUTO.equals(requestedHeight)) {
244: final long contentWidth = getContentWidth();
245: if (contentWidth > 0) {
246: // Intrinsic height must be computed to preserve the aspect ratio.
247: return computedWidth * getContentHeight()
248: / contentWidth;
249: }
250:
251: // use the intrinsic height ..
252: return getContentHeight();
253: }
254: // if height is not auto, then use the declared height.
255: else {
256: // A percentage is now relative to the intrinsinc size.
257: // And yes, I'm aware that this is not what the standard says ..
258: return requestedHeight.resolve(blockContextWidth);
259: }
260: } else {
261: // width is not auto.
262: // If the height is auto, we have to preserve the aspect ratio ..
263: if (RenderLength.AUTO.equals(requestedHeight)) {
264: final long contentWidth = getContentWidth();
265: if (contentWidth > 0) {
266: // Requested height must be computed to preserve the aspect ratio.
267: return computedWidth * getContentHeight()
268: / contentWidth;
269: } else {
270: return 0;
271: }
272: } else {
273: // height is something fixed ..
274: return requestedHeight.resolve(blockContextWidth);
275: }
276: }
277: }
278:
279: public Object getContentCached() {
280: return contentCached;
281: }
282:
283: public void setContentCached(final Object contentCached) {
284: this .contentCached = contentCached;
285: }
286:
287: /**
288: * Computes a relative content-width relative to the current block-context width.
289: * @return
290: */
291: public long getComputedContentWidth() {
292: return computeWidth(computeBlockContextWidth(this ));
293: }
294:
295: private long computeBlockContextWidth(final RenderNode box) {
296: final RenderBox parentBlockContext = box.getParent();
297: if (parentBlockContext == null) {
298: final LogicalPageBox logicalPage = box.getLogicalPage();
299: if (logicalPage == null) {
300: return 0;
301: }
302: return logicalPage.getPageWidth();
303: }
304: return parentBlockContext.getStaticBoxLayoutProperties()
305: .getBlockContextWidth();
306: }
307:
308: public String toString() {
309: return "RenderableReplacedContent{" +
310: // "content=" + content +
311: ", source=" + source + ", imageResolutionMapping="
312: + imageResolutionMapping + ", avoidPagebreaksInside="
313: + avoidPagebreaksInside + ", contentWidth="
314: + contentWidth + ", contentHeight=" + contentHeight
315: + ", requestedWidth=" + requestedWidth
316: + ", requestedHeight=" + requestedHeight
317: + ", minimumWidth=" + minimumWidth + ", minimumHeight="
318: + minimumHeight + ", maximumWidth=" + maximumWidth
319: + ", maximumHeight=" + maximumHeight + '}';
320: }
321: }
|