Package net.sf.jasperreports.engine.export

Source Code of net.sf.jasperreports.engine.export.JRTextExporter

/*
* JasperReports - Free Java Reporting Library.
* Copyright (C) 2001 - 2009 Jaspersoft Corporation. All rights reserved.
* http://www.jaspersoft.com
*
* Unless you have purchased a commercial license agreement from Jaspersoft,
* the following license terms apply:
*
* This program is part of JasperReports.
*
* JasperReports is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* JasperReports is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with JasperReports. If not, see <http://www.gnu.org/licenses/>.
*/
package net.sf.jasperreports.engine.export;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Arrays;
import java.util.List;
import java.util.StringTokenizer;

import net.sf.jasperreports.engine.JRAbstractExporter;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRExporterParameter;
import net.sf.jasperreports.engine.JRPrintFrame;
import net.sf.jasperreports.engine.JRPrintPage;
import net.sf.jasperreports.engine.JRPrintText;
import net.sf.jasperreports.engine.JRStyledTextAttributeSelector;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.util.JRProperties;
import net.sf.jasperreports.engine.util.JRStyledText;

/**
* Exports filled reports in plain text format. The text exporter allows users to define a custom character resolution
* (the number of columns and rows in text format). Since the character resolution is mapped on the actual pixel resolution,
* every character corresponds to a rectangle of pixels. If a certain text element has a smaller size in pixels (width,
* height, or both) than the number of pixels that map to a character, the text element will not be rendered. Because of
* this, users must take some precautions when creating reports for text export. First, they must make sure the page size in
* characters is large enough to render the report, because if the report pages contain too much text, some of it may be
* rendered only partially. On the other hand, if the character resolution is too small compared to the pixel resolution
* (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
* character, will not be displayed (in the previous example, a text element needs to be at least 800/20 = 40 pixels tall
* in order to be rendered).
* <p>
* As a conclusion, the text exporter will yield the better results if the space needed for displaying a text is large. So
* users have to either design reports with few text or export to big text pages. Another good practice is to arrange text
* elements at design time as similar as possible to a grid.
*
* @see JRExporterParameter
* @author Ionut Nedelcu (ionutned@users.sourceforge.net)
* @version $Id: JRTextExporter.java 3678 2010-04-02 12:13:06Z shertage $
*/
public class JRTextExporter extends JRAbstractExporter
{
  private static final String TXT_EXPORTER_PROPERTIES_PREFIX = JRProperties.PROPERTY_PREFIX + "export.txt.";

  protected int pageWidthInChars;
  protected int pageHeightInChars;
  protected float charWidth;
  protected float charHeight;
  protected JRExportProgressMonitor progressMonitor;
  protected Writer writer;
  char[][] pageData;
  protected String betweenPagesText;
  protected String lineSeparator;

  protected static final String systemLineSeparator = System.getProperty("line.separator");

  /**
   *
   */
  public void exportReport() throws JRException
  {
    progressMonitor = (JRExportProgressMonitor)parameters.get(JRExporterParameter.PROGRESS_MONITOR);

    /*   */
    setOffset();

    /*   */
    setInput();

    if (!parameters.containsKey(JRExporterParameter.FILTER))
    {
      filter = createFilter(TXT_EXPORTER_PROPERTIES_PREFIX);
    }

    /*   */
    if (!isModeBatch)
    {
      setPageRange();
    }

    String encoding =
      getStringParameterOrDefault(
        JRExporterParameter.CHARACTER_ENCODING,
        JRExporterParameter.PROPERTY_CHARACTER_ENCODING
        );

    betweenPagesText = (String) parameters.get(JRTextExporterParameter.BETWEEN_PAGES_TEXT);
    if (betweenPagesText == null)
    {
      betweenPagesText = systemLineSeparator + systemLineSeparator;
    }

    lineSeparator = (String) parameters.get(JRTextExporterParameter.LINE_SEPARATOR);
    if (lineSeparator == null)
    {
      lineSeparator = systemLineSeparator;
    }

    StringBuffer sb = (StringBuffer)parameters.get(JRExporterParameter.OUTPUT_STRING_BUFFER);
    if (sb != null)
    {
      try
      {
        writer = new StringWriter();
        exportReportToWriter();
        sb.append(writer.toString());
      }
      catch (IOException e)
      {
        throw new JRException("Error writing to StringBuffer writer : " + jasperPrint.getName(), e);
      }
      finally
      {
        if (writer != null)
        {
          try
          {
            writer.close();
          }
          catch(IOException e)
          {
          }
        }
      }
    }
    else
    {
      writer = (Writer)parameters.get(JRExporterParameter.OUTPUT_WRITER);
      if (writer != null)
      {
        try
        {
          exportReportToWriter();
        }
        catch (IOException e)
        {
          throw new JRException("Error writing to writer : " + jasperPrint.getName(), e);
        }
      }
      else
      {
        OutputStream os = (OutputStream)parameters.get(JRExporterParameter.OUTPUT_STREAM);
        if (os != null)
        {
          try
          {
            writer = new OutputStreamWriter(os, encoding);
            exportReportToWriter();
          }
          catch (IOException e)
          {
            throw new JRException("Error writing to OutputStream writer : " + jasperPrint.getName(), e);
          }
        }
        else
        {
          File destFile = (File)parameters.get(JRExporterParameter.OUTPUT_FILE);
          if (destFile == null)
          {
            String fileName = (String)parameters.get(JRExporterParameter.OUTPUT_FILE_NAME);
            if (fileName != null)
            {
              destFile = new File(fileName);
            }
            else
            {
              throw new JRException("No output specified for the exporter.");
            }
          }

          try
          {
            os = new FileOutputStream(destFile);
            writer = new OutputStreamWriter(os, encoding);
            exportReportToWriter();
          }
          catch (IOException e)
          {
            throw new JRException("Error writing to file writer : " + jasperPrint.getName(), e);
          }
          finally
          {
            if (writer != null)
            {
              try
              {
                writer.close();
              }
              catch(IOException e)
              {
              }
            }
          }
        }
      }
    }
  }


  /**
   *
   */
  public void setReportParameters() throws JRException
  {
    charWidth =
      getFloatParameter(
        JRTextExporterParameter.CHARACTER_WIDTH,
        JRTextExporterParameter.PROPERTY_CHARACTER_WIDTH,
        0
        );
    if (charWidth < 0)
    {
      throw new JRException("Character width in pixels must be greater than zero.");
    }
    else if (charWidth == 0)
    {
      pageWidthInChars =
        getIntegerParameter(
          JRTextExporterParameter.PAGE_WIDTH,
          JRTextExporterParameter.PROPERTY_PAGE_WIDTH,
          0
          );
      if (pageWidthInChars <= 0)
      {
        throw new JRException("Character width in pixels or page width in characters must be specified and must be greater than zero.");
      }
     
      charWidth = jasperPrint.getPageWidth() / (float)pageWidthInChars;
    }
    else
    {
      pageWidthInChars = (int)(jasperPrint.getPageWidth() / charWidth);
    }
   

    charHeight =
      getFloatParameter(
        JRTextExporterParameter.CHARACTER_HEIGHT,
        JRTextExporterParameter.PROPERTY_CHARACTER_HEIGHT,
        0
        );
    if (charHeight < 0)
    {
      throw new JRException("Character height in pixels must be greater than zero.");
    }
    else if (charHeight == 0)
    {
      pageHeightInChars =
        getIntegerParameter(
          JRTextExporterParameter.PAGE_HEIGHT,
          JRTextExporterParameter.PROPERTY_PAGE_HEIGHT,
          0
          );
      if (pageHeightInChars <= 0)
      {
        throw new JRException("Character height in pixels or page height in characters must be specified and must be greater than zero.");
      }

      charHeight = jasperPrint.getPageHeight() / (float)pageHeightInChars;
    }
    else
    {
      pageHeightInChars = (int)(jasperPrint.getPageHeight() / charHeight);
    }
  }


  /**
   *
   */
  protected void exportReportToWriter() throws JRException, IOException
  {
    for(int reportIndex = 0; reportIndex < jasperPrintList.size(); reportIndex++)
    {
      setJasperPrint((JasperPrint)jasperPrintList.get(reportIndex));

      List pages = jasperPrint.getPages();
      if (pages != null && pages.size() > 0)
      {
        if (isModeBatch)
        {
          startPageIndex = 0;
          endPageIndex = pages.size() - 1;
        }

        /*   */
        setReportParameters();//FIXMENOW check all report level exporter hints and make sure they are read from the current report, not from the first

        for(int i = startPageIndex; i <= endPageIndex; i++)
        {
          if (Thread.interrupted())
          {
            throw new JRException("Current thread interrupted.");
          }

          JRPrintPage page = (JRPrintPage)pages.get(i);

          /*   */
          exportPage(page);
        }
      }
    }

    writer.flush();
  }


  /**
   * Exports a page to the output writer. Only text elements within the page are considered. For each page, the engine
   * creates a matrix of characters and each rendered text element is placed at the appropiate position in the matrix.
   * After all texts are parsed, the character matrix is sent to the output writer.
   */
  protected void exportPage(JRPrintPage page) throws IOException
  {
    List elements = page.getElements();

    pageData = new char[pageHeightInChars][];
    for (int i = 0; i < pageHeightInChars; i++) {
      pageData[i] = new char[pageWidthInChars];
      Arrays.fill(pageData[i], ' ');
    }

    exportElements(elements);

    for (int i = 0; i < pageHeightInChars; i++) {
      writer.write(pageData[i]);
      writer.write(lineSeparator);
    }

    writer.write(betweenPagesText);

    if (progressMonitor != null)
    {
      progressMonitor.afterPageExport();
    }
  }


  protected void exportElements(List elements)
  {
    for (int i = 0; i < elements.size();i++)
    {
      Object element = elements.get(i);
      if (element instanceof JRPrintText)
      {
        exportText((JRPrintText) element);
      }
      else if (element instanceof JRPrintFrame)
      {
        JRPrintFrame frame = (JRPrintFrame) element;
        setFrameElementsOffset(frame, false);
        try
        {
          exportElements(frame.getElements());
        }
        finally
        {
          restoreElementOffsets();
        }
      }
    }
  }


  /**
   * Renders a text and places it in the output matrix.
   */
  protected void exportText(JRPrintText element)
  {
    int colSpan = getWidthInChars(element.getWidth());
    int rowSpan = getHeightInChars(element.getHeight());
    int col = getWidthInChars(element.getX() + getOffsetX());
    int row = getHeightInChars(element.getY() + getOffsetY());
   
    if (col + colSpan > pageWidthInChars)
    {
      //if the text exceeds the page width, truncate the column count
      colSpan = pageWidthInChars - col;
    }

    String allText;
    JRStyledText styledText = getStyledText(element);
    if (styledText == null)
    {
      allText = "";
    }
    else
    {
      allText = styledText.getText();
    }

    // if the space is too small, the element will not be rendered
    if (rowSpan <= 0 || colSpan <= 0)
    {
      return;
    }

    if (allText != null && allText.length() == 0)
    {
      return;
    }

    // uses an array of string buffers, since the maximum number of rows is already calculated
    StringBuffer[] rows = new StringBuffer[rowSpan];
    rows[0] = new StringBuffer();
    int rowIndex = 0;
    int rowPosition = 0;
    boolean isFirstLine = true;
   
    // first search for \n, because it causes immediate line break
    StringTokenizer lfTokenizer = new StringTokenizer(allText, "\n", true);
    label:while (lfTokenizer.hasMoreTokens()) {
      String line = lfTokenizer.nextToken();
      // if text starts with a new line:
      if(isFirstLine && line.equals("\n"))
      {
        rows[rowIndex].append("");
        rowIndex++;
        if(rowIndex == rowSpan || !lfTokenizer.hasMoreTokens())
        {
          break label;
        }
        rowPosition = 0;
        rows[rowIndex] = new StringBuffer();
        line = lfTokenizer.nextToken();
      }

      isFirstLine = false;
     
      // if there is a series of new lines:
      int emptyLinesCount = 0;
      while(line.equals("\n") && lfTokenizer.hasMoreTokens())
      {
        emptyLinesCount ++;
        line = lfTokenizer.nextToken();
      }
       
      if(emptyLinesCount > 1)
      {
        for(int i = 0; i < emptyLinesCount-1; i++)
        {
          rows[rowIndex].append("");
          rowIndex++;
          if(rowIndex == rowSpan)
          {
            break label;
          }
          rowPosition = 0;
          rows[rowIndex] = new StringBuffer();
          //if this is the last empty line:
          if(!lfTokenizer.hasMoreTokens() && line.equals("\n"))
          {
            rows[rowIndex].append("");
            break label;
          }
        }
      }
      if(!line.equals("\n"))
      {
       
        StringTokenizer spaceTokenizer = new StringTokenizer(line, " ", true);
 
        // divide each text line in words
        while (spaceTokenizer.hasMoreTokens()) {
          String word = spaceTokenizer.nextToken();
 
          // situation: word is larger than the entire column
          // in this case breaking occurs in the middle of the word
          while (word.length() > colSpan) {
            rows[rowIndex].append(word.substring(0, colSpan - rowPosition));
            word = word.substring(colSpan - rowPosition, word.length());
            rowIndex++;
            if(rowIndex == rowSpan)
            {
              break label;
            }
            rowPosition = 0;
            rows[rowIndex] = new StringBuffer();
          }
 
          // situation: word is larger than remaining space on the current line
          // in this case, go to the next line
          if (rowPosition + word.length() > colSpan)
          {
            rowIndex++;
            if (rowIndex == rowSpan)
            {
              break label;
            }
            rowPosition = 0;
            rows[rowIndex] = new StringBuffer();
          }
 
          // situation: the word is actually a space and it situated at the beginning of a new line
          // in this case, it is removed
          if (rowIndex > 0 && rowPosition == 0 && word.equals(" "))
          {
            continue;
          }
          // situation: the word is small enough to fit in the current line
          // in this case just add the word and increment the cursor position
          rows[rowIndex].append(word);
          rowPosition += word.length();
        }
 
 
        rowIndex++;
        if(rowIndex == rowSpan)
        {
          break;
        }
        rowPosition = 0;
        rows[rowIndex] = new StringBuffer();
      }
    }

    int colOffset = 0;
    int rowOffset = 0;

    switch (element.getVerticalAlignmentValue())
    {
      case BOTTOM :
      {
        rowOffset = rowSpan - rowIndex;
        break;
      }
      case MIDDLE :
      {
        rowOffset = (rowSpan - rowIndex) / 2;
        break;
      }
    }

    for (int i = 0; i < rowIndex; i++) {
      String line = rows[i].toString();
      int pos = line.length() - 1;
      while (pos >= 0 && line.charAt(pos) == ' ')
      {
        pos--;
      }
      line = line.substring(0, pos + 1);
      switch (element.getHorizontalAlignmentValue())
      {
        case RIGHT :
        {
          colOffset = colSpan - line.length();
          break;
        }
        case CENTER :
        {
          colOffset = (colSpan - line.length()) / 2;
          break;
        }
 
        // if text is justified, there is no offset, but the line text is modified
        // the last line in the paragraph is not justified.
        case JUSTIFIED :
        {
          if (i < rowIndex -1)
          {
            line = justifyText(line, colSpan);
          }
          break;
        }
      }

      char[] chars = line.toCharArray();
      System.arraycopy(chars, 0, pageData[row + rowOffset + i], col + colOffset, chars.length);
    }
  }


  /**
   * Justifies the text inside a specified space.
   */
  private String justifyText(String s, int width)
  {
    StringBuffer justified = new StringBuffer();

    StringTokenizer t = new StringTokenizer(s, " ");
    int tokenCount = t.countTokens();
    if (tokenCount <= 1)
    {
      return s;
    }

    String[] words = new String[tokenCount];
    int i = 0;
    while (t.hasMoreTokens())
    {
      words[i++] = t.nextToken();
    }

    int emptySpace = width - s.length() + (words.length - 1);
    int spaceCount = emptySpace / (words.length - 1);
    int remainingSpace = emptySpace % (words.length - 1);

    char[] spaces = new char[spaceCount];
    Arrays.fill(spaces, ' ');

    for (i = 0; i < words.length - 1; i++)
    {
      justified.append(words[i]);
      justified.append(spaces);
      if (i < remainingSpace)
      {
        justified.append(' ');
      }
    }
    justified.append(words[words.length-1]);

    return justified.toString();
  }


  /**
   * Transforms height from pixel space to character space.
   */
  protected int getHeightInChars(int height)
  {
    //return (int) (((long) pageHeightInChars * height) / jasperPrint.getPageHeight());
    return Math.round(height / charHeight);
  }

  /**
   * Transforms width from pixel space to character space.
   */
  protected int getWidthInChars(int width)
  {
//    return pageWidthInChars * width / jasperPrint.getPageWidth();
    return Math.round(width / charWidth);
  }


  /**
   *
   */
  protected JRStyledText getStyledText(JRPrintText textElement)
  {
    return textElement.getStyledText(JRStyledTextAttributeSelector.NONE);
  }

  /**
   *
   */
  protected String getExporterKey()
  {
    return null;
  }
}
TOP

Related Classes of net.sf.jasperreports.engine.export.JRTextExporter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.