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: * RTFTextExtractor.java
027: * ------------
028: * (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
029: */package org.jfree.report.modules.output.table.rtf.helper;
030:
031: import java.awt.Color;
032: import java.io.IOException;
033:
034: import com.lowagie.text.Chunk;
035: import com.lowagie.text.DocumentException;
036: import com.lowagie.text.Element;
037: import com.lowagie.text.Font;
038: import com.lowagie.text.Image;
039: import com.lowagie.text.Paragraph;
040: import com.lowagie.text.TextElementArray;
041: import com.lowagie.text.pdf.BaseFont;
042: import org.jfree.fonts.itext.BaseFontSupport;
043: import org.jfree.report.ImageContainer;
044: import org.jfree.report.InvalidReportStateException;
045: import org.jfree.report.layout.model.BlockRenderBox;
046: import org.jfree.report.layout.model.CanvasRenderBox;
047: import org.jfree.report.layout.model.InlineRenderBox;
048: import org.jfree.report.layout.model.ParagraphRenderBox;
049: import org.jfree.report.layout.model.RenderBox;
050: import org.jfree.report.layout.model.RenderNode;
051: import org.jfree.report.layout.model.RenderableReplacedContent;
052: import org.jfree.report.layout.model.RenderableText;
053: import org.jfree.report.layout.output.OutputProcessorMetaData;
054: import org.jfree.report.layout.output.RenderUtility;
055: import org.jfree.report.modules.output.table.base.DefaultTextExtractor;
056: import org.jfree.report.style.ElementStyleKeys;
057: import org.jfree.report.style.StyleSheet;
058: import org.jfree.report.style.TextStyleKeys;
059: import org.jfree.report.util.geom.StrictBounds;
060: import org.jfree.ui.Drawable;
061: import org.jfree.util.FastStack;
062:
063: /**
064: * Creation-Date: 10.05.2007, 19:49:46
065: *
066: * @author Thomas Morgner
067: */
068: public class RTFTextExtractor extends DefaultTextExtractor {
069: private class StyleContext {
070: private TextElementArray target;
071: private BaseFontSupport fontSupport;
072: private String fontName;
073: private double fontSize;
074: private boolean bold;
075: private boolean italic;
076: private boolean underline;
077: private boolean strikethrough;
078: private Color textColor;
079: private Color backgroundColor;
080:
081: protected StyleContext(final TextElementArray target,
082: final StyleSheet styleSheet,
083: final BaseFontSupport fontSupport) {
084: this .target = target;
085: this .fontSupport = fontSupport;
086: this .fontName = (String) styleSheet
087: .getStyleProperty(TextStyleKeys.FONT);
088: this .fontSize = styleSheet.getDoubleStyleProperty(
089: TextStyleKeys.FONTSIZE, 0);
090: this .bold = styleSheet
091: .getBooleanStyleProperty(TextStyleKeys.BOLD);
092: this .italic = styleSheet
093: .getBooleanStyleProperty(TextStyleKeys.ITALIC);
094: this .underline = styleSheet
095: .getBooleanStyleProperty(TextStyleKeys.UNDERLINED);
096: this .strikethrough = styleSheet
097: .getBooleanStyleProperty(TextStyleKeys.STRIKETHROUGH);
098: this .textColor = (Color) styleSheet
099: .getStyleProperty(ElementStyleKeys.PAINT);
100: this .backgroundColor = (Color) styleSheet
101: .getStyleProperty(ElementStyleKeys.BACKGROUND_COLOR);
102: }
103:
104: public TextElementArray getTarget() {
105: return target;
106: }
107:
108: public String getFontName() {
109: return fontName;
110: }
111:
112: public double getFontSize() {
113: return fontSize;
114: }
115:
116: public boolean isBold() {
117: return bold;
118: }
119:
120: public boolean isItalic() {
121: return italic;
122: }
123:
124: public boolean isUnderline() {
125: return underline;
126: }
127:
128: public boolean isStrikethrough() {
129: return strikethrough;
130: }
131:
132: public Color getTextColor() {
133: return textColor;
134: }
135:
136: public Color getBackgroundColor() {
137: return backgroundColor;
138: }
139:
140: public void add(final Element element) {
141: target.add(element);
142: }
143:
144: public boolean equals(final Object o) {
145: if (this == o) {
146: return true;
147: }
148: if (o == null || getClass() != o.getClass()) {
149: return false;
150: }
151:
152: final StyleContext that = (StyleContext) o;
153:
154: if (bold != that.bold) {
155: return false;
156: }
157: if (that.fontSize != fontSize) {
158: return false;
159: }
160: if (italic != that.italic) {
161: return false;
162: }
163: if (strikethrough != that.strikethrough) {
164: return false;
165: }
166: if (underline != that.underline) {
167: return false;
168: }
169: if (backgroundColor != null ? !backgroundColor
170: .equals(that.backgroundColor)
171: : that.backgroundColor != null) {
172: return false;
173: }
174: if (fontName != null ? !fontName.equals(that.fontName)
175: : that.fontName != null) {
176: return false;
177: }
178: if (textColor != null ? !textColor.equals(that.textColor)
179: : that.textColor != null) {
180: return false;
181: }
182:
183: return true;
184: }
185:
186: public int hashCode() {
187: int result = (fontName != null ? fontName.hashCode() : 0);
188: final long temp = fontSize != +0.0d ? Double
189: .doubleToLongBits(fontSize) : 0L;
190: result = 29 * result + (int) (temp ^ (temp >>> 32));
191: result = 29 * result + (bold ? 1 : 0);
192: result = 29 * result + (italic ? 1 : 0);
193: result = 29 * result + (underline ? 1 : 0);
194: result = 29 * result + (strikethrough ? 1 : 0);
195: result = 29 * result
196: + (textColor != null ? textColor.hashCode() : 0);
197: result = 29
198: * result
199: + (backgroundColor != null ? backgroundColor
200: .hashCode() : 0);
201: return result;
202: }
203:
204: public void add(final String text) {
205: int style = Font.NORMAL;
206: if (bold) {
207: style |= Font.BOLD;
208: }
209: if (italic) {
210: style |= Font.ITALIC;
211: }
212: if (strikethrough) {
213: style |= Font.STRIKETHRU;
214: }
215: if (underline) {
216: style |= Font.UNDERLINE;
217: }
218:
219: final BaseFont baseFont = fontSupport.createBaseFont(
220: fontName, bold, italic, "utf-8", false);
221: final Font font = new Font(baseFont, (float) fontSize,
222: style, textColor);
223: final Chunk c = new Chunk(text, font);
224: if (backgroundColor != null) {
225: c.setBackground(backgroundColor);
226: }
227: target.add(c);
228: }
229: }
230:
231: private RTFImageCache imageCache;
232: private FastStack context;
233: private OutputProcessorMetaData metaData;
234: private BaseFontSupport fontSupport;
235: private boolean handleImages;
236:
237: public RTFTextExtractor(final OutputProcessorMetaData metaData) {
238: super (metaData);
239: this .handleImages = metaData
240: .isFeatureSupported(RTFOutputProcessorMetaData.IMAGES_ENABLED);
241: context = new FastStack();
242: }
243:
244: private StyleContext getCurrentContext() {
245: return (StyleContext) context.peek();
246: }
247:
248: public void compute(final RenderBox box,
249: final TextElementArray cell,
250: final RTFImageCache imageCache,
251: final OutputProcessorMetaData metaData,
252: final BaseFontSupport fontSupport) {
253: this .metaData = metaData;
254: this .fontSupport = fontSupport;
255: this .context.clear();
256: this .context.push(new StyleContext(cell, box.getStyleSheet(),
257: fontSupport));
258: this .imageCache = imageCache;
259: getParagraphBounds().setRect(box.getX(), box.getY(),
260: box.getWidth(), box.getHeight());
261:
262: startProcessing(box);
263: }
264:
265: protected boolean startInlineBox(final InlineRenderBox box) {
266: // Compare the text style ..
267: final StyleContext currentContext = getCurrentContext();
268: final StyleContext boxContext = new StyleContext(currentContext
269: .getTarget(), box.getStyleSheet(), fontSupport);
270: if (currentContext.equals(boxContext) == false) {
271: if (getTextLength() > 0) {
272: final String text = getText();
273: currentContext.add(text);
274: clearText();
275: }
276: this .context.pop();
277: this .context.push(boxContext);
278: }
279: return true;
280: }
281:
282: protected void finishInlineBox(final InlineRenderBox box) {
283: final StyleContext currentContext = getCurrentContext();
284: if (getTextLength() > 0) {
285: final String text = getText();
286: currentContext.add(text);
287: clearText();
288: }
289: }
290:
291: protected void processOtherNode(final RenderNode node) {
292: final StrictBounds paragraphBounds = getParagraphBounds();
293: if (node.isNodeVisible(paragraphBounds) == false) {
294: return;
295: }
296:
297: try {
298: super .processOtherNode(node);
299: if (node instanceof RenderableText) {
300: if (node.isVirtualNode()) {
301: return;
302: }
303:
304: if ((node.getX() + node.getWidth()) > (paragraphBounds
305: .getX() + paragraphBounds.getWidth())) {
306: // This node will only be partially visible. The end-of-line marker will not apply.
307: return;
308: }
309: final RenderableText text = (RenderableText) node;
310: if (text.isForceLinebreak()) {
311: final StyleContext currentContext = getCurrentContext();
312: if (getTextLength() > 0) {
313: currentContext.add(getText());
314: clearText();
315: }
316: context.pop();
317: final StyleContext cellContext = getCurrentContext();
318: cellContext.add(currentContext.getTarget());
319:
320: context.push(new StyleContext(new Paragraph(), text
321: .getStyleSheet(), fontSupport));
322: }
323: } else if (node instanceof RenderableReplacedContent
324: && handleImages) {
325: final RenderableReplacedContent rpc = (RenderableReplacedContent) node;
326: processReplacedContent(rpc, node);
327: }
328: } catch (DocumentException ioe) {
329: throw new InvalidReportStateException(
330: "Failed to extract text", ioe);
331: } catch (IOException e) {
332: // double ignore ..
333: throw new InvalidReportStateException(
334: "Failed to extract text", e);
335: }
336: }
337:
338: private void processReplacedContent(
339: final RenderableReplacedContent rpc, final RenderNode node)
340: throws DocumentException, IOException {
341: final Object rawObject = rpc.getRawObject();
342: if (rawObject instanceof ImageContainer) {
343: final Image image = imageCache
344: .getImage((ImageContainer) rawObject);
345: final StyleContext currentContext = getCurrentContext();
346: if (getTextLength() > 0) {
347: currentContext.add(getText());
348: clearText();
349: }
350: currentContext.add(image);
351: } else if (rawObject instanceof Drawable) {
352: final StrictBounds rect = new StrictBounds(node.getX(),
353: node.getY(), node.getWidth(), node.getHeight());
354: final ImageContainer ic = RenderUtility
355: .createImageFromDrawable((Drawable) rawObject,
356: rect, node, metaData);
357: final Image image = imageCache.getImage(ic);
358: final StyleContext currentContext = getCurrentContext();
359: if (getTextLength() > 0) {
360: currentContext.add(getText());
361: clearText();
362: }
363: currentContext.add(image);
364: }
365: }
366:
367: public boolean startCanvasBox(final CanvasRenderBox box) {
368: return true;
369: }
370:
371: protected boolean startBlockBox(final BlockRenderBox box) {
372: return true;
373: }
374:
375: protected void processParagraphChilds(final ParagraphRenderBox box) {
376: context.push(new StyleContext(new Paragraph(), box
377: .getStyleSheet(), fontSupport));
378: clearText();
379:
380: super .processParagraphChilds(box);
381:
382: final StyleContext currentContext = getCurrentContext();
383: if (getTextLength() > 0) {
384: currentContext.add(getText());
385: clearText();
386: }
387: context.pop();
388: getCurrentContext().add(currentContext.getTarget());
389: }
390:
391: }
|