KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > jasperreports > engine > export > JRTextExporter


1 /*
2  * ============================================================================
3  * GNU Lesser General Public License
4  * ============================================================================
5  *
6  * JasperReports - Free Java report-generating library.
7  * Copyright (C) 2001-2006 JasperSoft Corporation http://www.jaspersoft.com
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
22  *
23  * JasperSoft Corporation
24  * 303 Second Street, Suite 450 North
25  * San Francisco, CA 94107
26  * http://www.jaspersoft.com
27  */

28 package net.sf.jasperreports.engine.export;
29
30 import java.io.File JavaDoc;
31 import java.io.FileOutputStream JavaDoc;
32 import java.io.IOException JavaDoc;
33 import java.io.OutputStream JavaDoc;
34 import java.io.OutputStreamWriter JavaDoc;
35 import java.io.StringWriter JavaDoc;
36 import java.io.Writer JavaDoc;
37 import java.util.Arrays JavaDoc;
38 import java.util.List JavaDoc;
39 import java.util.StringTokenizer JavaDoc;
40
41 import net.sf.jasperreports.engine.JRAbstractExporter;
42 import net.sf.jasperreports.engine.JRAlignment;
43 import net.sf.jasperreports.engine.JRException;
44 import net.sf.jasperreports.engine.JRExporterParameter;
45 import net.sf.jasperreports.engine.JRPrintFrame;
46 import net.sf.jasperreports.engine.JRPrintPage;
47 import net.sf.jasperreports.engine.JRPrintText;
48 import net.sf.jasperreports.engine.JasperPrint;
49 import net.sf.jasperreports.engine.util.JRStyledText;
50 import net.sf.jasperreports.engine.util.JRStyledTextParser;
51
52 import org.xml.sax.SAXException JavaDoc;
53
54 /**
55  * Exports filled reports in plain text format. The text exporter allows users to define a custom character resolution
56  * (the number of columns and rows in text format). Since the character resolution is mapped on the actual pixel resolution,
57  * every character corresponds to a rectangle of pixels. If a certain text element has a smaller size in pixels (width,
58  * height, or both) than the number of pixels that map to a character, the text element will not be rendered. Because of
59  * this, users must take some precautions when creating reports for text export. First, they must make sure the page size in
60  * characters is large enough to render the report, because if the report pages contain too much text, some of it may be
61  * rendered only partially. On the other hand, if the character resolution is too small compared to the pixel resolution
62  * (say, a height of 20 characters for a page 800 pixels tall) all texts with sizes smaller than the one needed to map to a
63  * character, will not be displayed (in the previous examplle, a text element needs to be at least 800/20 = 40 pixels tall
64  * in order to be rendered).
65  * <p>
66  * As a conclusion, the text exporter will yield the better results if the space needed for displaying a text is large. So
67  * users have to either design reports with few text or export to big text pages. Another good practice is to arrange text
68  * elements at design time as similar as possible to a grid.
69  *
70  * @see JRExporterParameter
71  * @author Ionut Nedelcu (ionutned@users.sourceforge.net)
72  * @version $Id: JRTextExporter.java 1413 2006-09-28 13:47:40 +0300 (Thu, 28 Sep 2006) teodord $
73  */

74 public class JRTextExporter extends JRAbstractExporter
75 {
76     protected int pageWidth;
77     protected int pageHeight;
78     protected int characterHeight;
79     protected int characterWidth;
80     protected JRExportProgressMonitor progressMonitor;
81     protected Writer JavaDoc writer;
82     char[][] pageData;
83     protected String JavaDoc betweenPagesText;
84     protected String JavaDoc lineSeparator;
85
86     protected static final String JavaDoc systemLineSeparator = System.getProperty("line.separator");
87     /**
88      *
89      */

90     protected JRStyledTextParser styledTextParser = new JRStyledTextParser();
91
92     /**
93      *
94      */

95     public void exportReport() throws JRException
96     {
97         progressMonitor = (JRExportProgressMonitor)parameters.get(JRExporterParameter.PROGRESS_MONITOR);
98
99         /* */
100         setOffset();
101
102         /* */
103         setInput();
104
105         /* */
106         if (!isModeBatch)
107         {
108             setPageRange();
109         }
110
111         String JavaDoc encoding = (String JavaDoc)parameters.get(JRExporterParameter.CHARACTER_ENCODING);
112         if (encoding == null)
113         {
114             encoding = "ISO-8859-1";
115         }
116
117         Integer JavaDoc characterWidthParam = (Integer JavaDoc) parameters.get(JRTextExporterParameter.CHARACTER_WIDTH);
118         if (characterWidthParam != null) {
119             characterWidth = characterWidthParam.intValue();
120             if (characterWidth < 0)
121                 throw new JRException("Character width must be greater than 0");
122         }
123         else {
124             Integer JavaDoc pageWidthParam = (Integer JavaDoc) parameters.get(JRTextExporterParameter.PAGE_WIDTH);
125             if (pageWidthParam != null) {
126                 pageWidth = pageWidthParam.intValue();
127                 if (pageWidth <= 0)
128                     throw new JRException("Page width must be greater than 0");
129             } else {
130                 throw new JRException("Character or page width must be specified");
131             }
132         }
133
134
135         Integer JavaDoc characterHeightParam = (Integer JavaDoc) parameters.get(JRTextExporterParameter.CHARACTER_HEIGHT);
136         if (characterHeightParam != null) {
137             characterHeight = characterHeightParam.intValue();
138             if (characterHeight < 0)
139                 throw new JRException("Character height must be greater than 0");
140         }
141         else {
142             Integer JavaDoc pageHeightParam = (Integer JavaDoc) parameters.get(JRTextExporterParameter.PAGE_HEIGHT);
143             if (pageHeightParam != null) {
144                 pageHeight = pageHeightParam.intValue();
145                 if (pageHeight <= 0)
146                     throw new JRException("Page height must be greater than 0");
147             }
148             else {
149                 throw new JRException("Character or page height must be specified");
150             }
151         }
152
153
154         betweenPagesText = (String JavaDoc) parameters.get(JRTextExporterParameter.BETWEEN_PAGES_TEXT);
155         if (betweenPagesText == null) {
156             betweenPagesText = systemLineSeparator + systemLineSeparator;
157         }
158
159         lineSeparator = (String JavaDoc) parameters.get(JRTextExporterParameter.LINE_SEPARATOR);
160         if (lineSeparator == null) {
161             lineSeparator = systemLineSeparator;
162         }
163
164         StringBuffer JavaDoc sb = (StringBuffer JavaDoc)parameters.get(JRExporterParameter.OUTPUT_STRING_BUFFER);
165         if (sb != null)
166         {
167             try
168             {
169                 writer = new StringWriter JavaDoc();
170                 exportReportToWriter();
171                 sb.append(writer.toString());
172             }
173             catch (IOException JavaDoc e)
174             {
175                 throw new JRException("Error writing to StringBuffer writer : " + jasperPrint.getName(), e);
176             }
177             finally
178             {
179                 if (writer != null)
180                 {
181                     try
182                     {
183                         writer.close();
184                     }
185                     catch(IOException JavaDoc e)
186                     {
187                     }
188                 }
189             }
190         }
191         else
192         {
193             writer = (Writer JavaDoc)parameters.get(JRExporterParameter.OUTPUT_WRITER);
194             if (writer != null)
195             {
196                 try
197                 {
198                     exportReportToWriter();
199                 }
200                 catch (IOException JavaDoc e)
201                 {
202                     throw new JRException("Error writing to writer : " + jasperPrint.getName(), e);
203                 }
204             }
205             else
206             {
207                 OutputStream JavaDoc os = (OutputStream JavaDoc)parameters.get(JRExporterParameter.OUTPUT_STREAM);
208                 if (os != null)
209                 {
210                     try
211                     {
212                         writer = new OutputStreamWriter JavaDoc(os, encoding);
213                         exportReportToWriter();
214                     }
215                     catch (IOException JavaDoc e)
216                     {
217                         throw new JRException("Error writing to OutputStream writer : " + jasperPrint.getName(), e);
218                     }
219                 }
220                 else
221                 {
222                     File JavaDoc destFile = (File JavaDoc)parameters.get(JRExporterParameter.OUTPUT_FILE);
223                     if (destFile == null)
224                     {
225                         String JavaDoc fileName = (String JavaDoc)parameters.get(JRExporterParameter.OUTPUT_FILE_NAME);
226                         if (fileName != null)
227                         {
228                             destFile = new File JavaDoc(fileName);
229                         }
230                         else
231                         {
232                             throw new JRException("No output specified for the exporter.");
233                         }
234                     }
235
236                     try
237                     {
238                         os = new FileOutputStream JavaDoc(destFile);
239                         writer = new OutputStreamWriter JavaDoc(os, encoding);
240                         exportReportToWriter();
241                     }
242                     catch (IOException JavaDoc e)
243                     {
244                         throw new JRException("Error writing to file writer : " + jasperPrint.getName(), e);
245                     }
246                     finally
247                     {
248                         if (writer != null)
249                         {
250                             try
251                             {
252                                 writer.close();
253                             }
254                             catch(IOException JavaDoc e)
255                             {
256                             }
257                         }
258                     }
259                 }
260             }
261         }
262     }
263
264
265     /**
266      *
267      */

268     protected void exportReportToWriter() throws JRException, IOException JavaDoc
269     {
270         for(int reportIndex = 0; reportIndex < jasperPrintList.size(); reportIndex++)
271         {
272             jasperPrint = (JasperPrint)jasperPrintList.get(reportIndex);
273
274             List JavaDoc pages = jasperPrint.getPages();
275             if (pages != null && pages.size() > 0)
276             {
277                 if (isModeBatch)
278                 {
279                     startPageIndex = 0;
280                     endPageIndex = pages.size() - 1;
281                 }
282
283                 if (characterWidth > 0)
284                     pageWidth = jasperPrint.getPageWidth() / characterWidth;
285                 if (characterHeight > 0)
286                     pageHeight = jasperPrint.getPageHeight() / characterHeight;
287
288                 for(int i = startPageIndex; i <= endPageIndex; i++)
289                 {
290                     if (Thread.currentThread().isInterrupted())
291                     {
292                         throw new JRException("Current thread interrupted.");
293                     }
294
295                     JRPrintPage page = (JRPrintPage)pages.get(i);
296
297                     /* */
298                     exportPage(page);
299                 }
300             }
301         }
302
303         writer.flush();
304     }
305
306
307     /**
308      * Exports a page to the output writer. Only text elements within the page are considered. For each page, the engine
309      * creates a matrix of characters and each rendered text element is placed at the appropiate position in the matrix.
310      * After all texts are parsed, the character matrix is sent to the output writer.
311      */

312     protected void exportPage(JRPrintPage page) throws IOException JavaDoc
313     {
314         List JavaDoc elements = page.getElements();
315
316         pageData = new char[pageHeight][];
317         for (int i = 0; i < pageHeight; i++) {
318             pageData[i] = new char[pageWidth];
319             Arrays.fill(pageData[i], ' ');
320         }
321
322         exportElements(elements);
323
324         for (int i = 0; i < pageHeight; i++) {
325             writer.write(pageData[i]);
326             writer.write(lineSeparator);
327         }
328
329         writer.write(betweenPagesText);
330
331         if (progressMonitor != null)
332         {
333             progressMonitor.afterPageExport();
334         }
335     }
336
337
338     protected void exportElements(List JavaDoc elements)
339     {
340         for (int i = 0; i < elements.size();i++)
341         {
342             Object JavaDoc element = elements.get(i);
343             if (element instanceof JRPrintText)
344             {
345                 exportText((JRPrintText) element);
346             }
347             else if (element instanceof JRPrintFrame)
348             {
349                 JRPrintFrame frame = (JRPrintFrame) element;
350                 setFrameElementsOffset(frame, false);
351                 try
352                 {
353                     exportElements(frame.getElements());
354                 }
355                 finally
356                 {
357                     restoreElementOffsets();
358                 }
359             }
360         }
361     }
362
363
364     /**
365      * Renders a text and places it in the output matrix.
366      */

367     protected void exportText(JRPrintText element)
368     {
369         int rowCount = calculateYCoord(element.getHeight());
370         int columnCount = calculateXCoord(element.getWidth());
371         int x = calculateXCoord(element.getX() + getOffsetX());
372         int y = calculateYCoord(element.getY() + getOffsetY());
373
374         String JavaDoc allText;
375         JRStyledText styledText = getStyledText(element);
376         if (styledText == null)
377         {
378             allText = "";
379         }
380         else
381         {
382             allText = styledText.getText();
383         }
384
385         // if the space is too small, the element will not be rendered
386
if (rowCount <= 0 || columnCount <= 0)
387             return;
388
389         if (allText != null && allText.length() == 0)
390             return;
391
392         // uses an array of string buffers, since the maximum number of rows is already calculated
393
StringBuffer JavaDoc[] rows = new StringBuffer JavaDoc[rowCount];
394         rows[0] = new StringBuffer JavaDoc();
395         int rowIndex = 0;
396         int rowPosition = 0;
397
398         // first search for \n, because it causes immediate line break
399
StringTokenizer JavaDoc lfTokenizer = new StringTokenizer JavaDoc(allText, "\n");
400         label:while (lfTokenizer.hasMoreTokens()) {
401             String JavaDoc line = lfTokenizer.nextToken();
402             StringTokenizer JavaDoc spaceTokenizer = new StringTokenizer JavaDoc(line, " ", true);
403
404             // divide each text line in words
405
while (spaceTokenizer.hasMoreTokens()) {
406                 String JavaDoc word = spaceTokenizer.nextToken();
407
408                 // situation: word is larger than the entire column
409
// in this case breaking occurs in the middle of the word
410
while (word.length() > columnCount) {
411                     rows[rowIndex].append(word.substring(0, columnCount - rowPosition));
412                     word = word.substring(columnCount - rowPosition, word.length());
413                     rowIndex++;
414                     if(rowIndex == rowCount)
415                         break label;
416                     rowPosition = 0;
417                     rows[rowIndex] = new StringBuffer JavaDoc();
418                 }
419
420                 // situation: word is larger than remaining space on the current line
421
// in this case, go to the next line
422
if (rowPosition + word.length() > columnCount) {
423                     rowIndex++;
424                     if (rowIndex == rowCount)
425                         break label;
426                     rowPosition = 0;
427                     rows[rowIndex] = new StringBuffer JavaDoc();
428                 }
429
430                 // situation: the word is actually a space and it situated at the beginning of a new line
431
// in this case, it is removed
432
if (rowIndex > 9 && rowPosition == 0 && word.equals(" "))
433                     break;
434
435                 // situation: the word is small enough to fit in the current line
436
// in this case just add the word and increment the cursor position
437
rows[rowIndex].append(word);
438                 rowPosition += word.length();
439             }
440
441
442             rowIndex++;
443             if(rowIndex == rowCount)
444                 break;
445             rowPosition = 0;
446             rows[rowIndex] = new StringBuffer JavaDoc();
447         }
448
449
450         int xOffset = 0;
451         int yOffset = 0;
452
453         if (element.getVerticalAlignment() == JRAlignment.VERTICAL_ALIGN_BOTTOM)
454             yOffset = rowCount - rowIndex;
455         if (element.getVerticalAlignment() == JRAlignment.VERTICAL_ALIGN_MIDDLE)
456             yOffset = (rowCount - rowIndex) / 2;
457
458         for (int i = 0; i < rowIndex; i++) {
459             String JavaDoc line = rows[i].toString();
460             int pos = line.length() - 1;
461             while (pos >= 0 && line.charAt(pos) == ' ')
462                 pos--;
463             line = line.substring(0, pos + 1);
464             if (element.getHorizontalAlignment() == JRAlignment.HORIZONTAL_ALIGN_RIGHT)
465                 xOffset = columnCount - line.length();
466             if (element.getHorizontalAlignment() == JRAlignment.HORIZONTAL_ALIGN_CENTER)
467                 xOffset = (columnCount - line.length()) / 2;
468
469             // if text is justified, there is no offset, but the line text is modified
470
// the last line in the paragraph is not justified.
471
if (element.getHorizontalAlignment() == JRAlignment.HORIZONTAL_ALIGN_JUSTIFIED)
472                 if (i < rowIndex -1)
473                     line = justifyText(line, columnCount);
474
475             char[] chars = line.toCharArray();
476             System.arraycopy(chars, 0, pageData[y + yOffset + i], x + xOffset, chars.length);
477         }
478     }
479
480
481     /**
482      * Justifies the text inside a specified space.
483      */

484     private String JavaDoc justifyText(String JavaDoc s, int width)
485     {
486         StringBuffer JavaDoc justified = new StringBuffer JavaDoc();
487
488         StringTokenizer JavaDoc t = new StringTokenizer JavaDoc(s, " ");
489         int tokenCount = t.countTokens();
490         if (tokenCount <= 1)
491             return s;
492
493         String JavaDoc[] words = new String JavaDoc[tokenCount];
494         int i = 0;
495         while (t.hasMoreTokens())
496             words[i++] = t.nextToken();
497
498         int emptySpace = width - s.length() + (words.length - 1);
499         int spaceCount = emptySpace / (words.length - 1);
500         int remainingSpace = emptySpace % (words.length - 1);
501
502         char[] spaces = new char[spaceCount];
503         Arrays.fill(spaces, ' ');
504
505         for (i = 0; i < words.length - 1; i++)
506         {
507             justified.append(words[i]);
508             justified.append(spaces);
509             if (i < remainingSpace)
510                 justified.append(' ');
511         }
512         justified.append(words[words.length-1]);
513
514         return justified.toString();
515     }
516
517
518     /**
519      * Transforms y coordinates from pixel space to character space.
520      */

521     protected int calculateYCoord(int y)
522     {
523         return pageHeight * y / jasperPrint.getPageHeight();
524     }
525
526     /**
527      * Transforms x coordinates from pixel space to character space.
528      */

529     protected int calculateXCoord(int x)
530     {
531         return pageWidth * x / jasperPrint.getPageWidth();
532     }
533
534
535     /**
536      *
537      */

538     protected JRStyledText getStyledText(JRPrintText textElement)
539     {
540         JRStyledText styledText = null;
541
542         String JavaDoc text = textElement.getText();
543         if (text != null)
544         {
545             if (textElement.isStyledText())
546             {
547                 try
548                 {
549                     styledText = styledTextParser.parse(null, text);
550                 }
551                 catch (SAXException JavaDoc e)
552                 {
553                     //ignore if invalid styled text and treat like normal text
554
}
555             }
556
557             if (styledText == null)
558             {
559                 styledText = new JRStyledText();
560                 styledText.append(text);
561                 styledText.addRun(new JRStyledText.Run(null, 0, text.length()));
562             }
563         }
564
565         return styledText;
566     }
567
568 }
569
Popular Tags