Package net.sf.jasperreports.engine.export

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

/*
* 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.awt.font.FontRenderContext;
import java.awt.font.LineBreakMeasurer;
import java.awt.font.TextLayout;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

import net.sf.jasperreports.engine.JRParagraph;
import net.sf.jasperreports.engine.JRPrintText;
import net.sf.jasperreports.engine.JRStyledTextAttributeSelector;
import net.sf.jasperreports.engine.TabStop;
import net.sf.jasperreports.engine.fill.TextMeasurer;
import net.sf.jasperreports.engine.type.HorizontalAlignEnum;
import net.sf.jasperreports.engine.util.JRStringUtil;
import net.sf.jasperreports.engine.util.JRStyledText;
import net.sf.jasperreports.engine.util.ParagraphUtil;


/**
* @author Teodor Danciu (teodord@users.sourceforge.net)
* @version $Id: TextRenderer.java 4280 2011-04-11 10:36:24Z teodord $
*/
public abstract class AbstractTextRenderer
{
  public static final FontRenderContext LINE_BREAK_FONT_RENDER_CONTEXT = new FontRenderContext(null, true, true);

  protected JRPrintText text;
  protected JRStyledText styledText;
  protected String allText;
  protected int x;
  protected int y;
  protected int width;
  protected int height;
  protected int topPadding;
  protected int leftPadding;
  protected int bottomPadding;
  protected int rightPadding;
 
  //protected float formatWidth;
  protected float verticalAlignOffset;
  protected float drawPosY;
  protected float drawPosX;
  protected float lineHeight;
  protected boolean isMaxHeightReached;
  protected List<TabSegment> segments;
  protected int segmentIndex;
 
  /**
   *
   *
  private MaxFontSizeFinder maxFontSizeFinder;
 
  /**
   *
   */
  private boolean isMinimizePrinterJobSize = true;
  private boolean ignoreMissingFont;

 
  /**
   *
   */
  public AbstractTextRenderer(
    boolean isMinimizePrinterJobSize,
    boolean ignoreMissingFont
    )
  {
    this.isMinimizePrinterJobSize = isMinimizePrinterJobSize;
    this.ignoreMissingFont = ignoreMissingFont;
  }
 
 
  /**
   *
   */
  public int getX()
  {
    return x;
  }
 
 
  /**
   *
   */
  public int getY()
  {
    return y;
  }
 
 
  /**
   *
   */
  public int getWidth()
  {
    return width;
  }
 
 
  /**
   *
   */
  public int getHeight()
  {
    return height;
  }
 
 
  /**
   *
   */
  public JRStyledText getStyledText()
  {
    return styledText;
  }
 
 
  /**
   *
   */
  public String getPlainText()
  {
    return allText;
  }
 
 
  /**
   *
   */
  public void initialize(JRPrintText text, int offsetX, int offsetY)
  {
    styledText = text.getStyledText(JRStyledTextAttributeSelector.NO_BACKCOLOR);
   
    if (styledText == null)
    {
      return;
    }

    allText = styledText.getText();
   
    x = text.getX() + offsetX;
    y = text.getY() + offsetY;
    width = text.getWidth();
    height = text.getHeight();
    topPadding = text.getLineBox().getTopPadding().intValue();
    leftPadding = text.getLineBox().getLeftPadding().intValue();
    bottomPadding = text.getLineBox().getBottomPadding().intValue();
    rightPadding = text.getLineBox().getRightPadding().intValue();
   
    switch (text.getRotationValue())
    {
      case LEFT :
      {
        y = text.getY() + offsetY + text.getHeight();
        width = text.getHeight();
        height = text.getWidth();
        int tmpPadding = topPadding;
        topPadding = leftPadding;
        leftPadding = bottomPadding;
        bottomPadding = rightPadding;
        rightPadding = tmpPadding;
        break;
      }
      case RIGHT :
      {
        x = text.getX() + offsetX + text.getWidth();
        width = text.getHeight();
        height = text.getWidth();
        int tmpPadding = topPadding;
        topPadding = rightPadding;
        rightPadding = bottomPadding;
        bottomPadding = leftPadding;
        leftPadding = tmpPadding;
        break;
      }
      case UPSIDE_DOWN :
      {
        int tmpPadding = topPadding;
        x = text.getX() + offsetX + text.getWidth();
        y = text.getY() + offsetY + text.getHeight();
        topPadding = bottomPadding;
        bottomPadding = tmpPadding;
        tmpPadding = leftPadding;
        leftPadding = rightPadding;
        rightPadding = tmpPadding;
        break;
      }
      case NONE :
      default :
      {
      }
    }
   
    this.text = text;

    verticalAlignOffset = 0f;
    switch (text.getVerticalAlignmentValue())
    {
      case TOP :
      {
        verticalAlignOffset = 0f;
        break;
      }
      case MIDDLE :
      {
        verticalAlignOffset = (height - topPadding - bottomPadding - text.getTextHeight()) / 2f;
        break;
      }
      case BOTTOM :
      {
        verticalAlignOffset = height - topPadding - bottomPadding - text.getTextHeight();
        break;
      }
      default :
      {
        verticalAlignOffset = 0f;
      }
    }

//    formatWidth = width - leftPadding - rightPadding;
//    formatWidth = formatWidth < 0 ? 0 : formatWidth;

    drawPosY = 0;
    drawPosX = 0;
 
    isMaxHeightReached = false;
   
    //maxFontSizeFinder = MaxFontSizeFinder.getInstance(!JRCommonText.MARKUP_NONE.equals(text.getMarkup()));
  }
 

  /**
   *
   */
  public void render()
  {
    AttributedCharacterIterator allParagraphs = 
      styledText.getAwtAttributedString(ignoreMissingFont).getIterator();

    int tokenPosition = 0;
    int lastParagraphStart = 0;
    String lastParagraphText = null;

    StringTokenizer tkzer = new StringTokenizer(allText, "\n", true);

    // text is split into paragraphs, using the newline character as delimiter
    while(tkzer.hasMoreTokens() && !isMaxHeightReached)
    {
      String token = tkzer.nextToken();

      if ("\n".equals(token))
      {
        renderParagraph(allParagraphs, lastParagraphStart, lastParagraphText);

        lastParagraphStart = tokenPosition;
        lastParagraphText = null;
      }
      else
      {
        lastParagraphStart = tokenPosition;
        lastParagraphText = token;
      }

      tokenPosition += token.length();
    }

    if (!isMaxHeightReached && lastParagraphStart < allText.length())
    {
      renderParagraph(allParagraphs, lastParagraphStart, lastParagraphText);
    }
  }


  /**
   *
   */
  private void renderParagraph(
    AttributedCharacterIterator allParagraphs,
    int lastParagraphStart,
    String lastParagraphText
    )
  {
    AttributedCharacterIterator paragraph = null;
   
    if (lastParagraphText == null)
    {
      lastParagraphText = " ";
      paragraph =
        new AttributedString(
          lastParagraphText,
          new AttributedString(
            allParagraphs,
            lastParagraphStart,
            lastParagraphStart + lastParagraphText.length()
            ).getIterator().getAttributes()
          ).getIterator();
    }
    else
    {
      paragraph =
        new AttributedString(
          allParagraphs,
          lastParagraphStart,
          lastParagraphStart + lastParagraphText.length()
          ).getIterator();
    }

    List<Integer> tabIndexes = JRStringUtil.getTabIndexes(lastParagraphText);
   
    int currentTab = 0;
    int lines = 0;
    float endX = 0;
   
    TabStop nextTabStop = null;
    boolean requireNextWord = false;
 
    LineBreakMeasurer lineMeasurer = new LineBreakMeasurer(paragraph, getFontRenderContext());//grx.getFontRenderContext()

    // the paragraph is rendered one line at a time
    while (lineMeasurer.getPosition() < paragraph.getEndIndex() && !isMaxHeightReached)
    {
      boolean lineComplete = false;

      float maxAscent = 0;
      float maxDescent = 0;
      float maxLeading = 0;
     
      // each line is split into segments, using the tab character as delimiter
      segments = new ArrayList<TabSegment>(1);

      TabSegment oldSegment = null;
      TabSegment crtSegment = null;

      // splitting the current line into tab segments
      while (!lineComplete)
      {
        // the current segment limit is either the next tab character or the paragraph end
        int tabIndexOrEndIndex = (tabIndexes == null || currentTab >= tabIndexes.size() ? paragraph.getEndIndex() : tabIndexes.get(currentTab) + 1);
       
        float startX = (lineMeasurer.getPosition() == 0 ? text.getParagraph().getFirstLineIndent() : 0);
        endX = width - text.getParagraph().getRightIndent() - rightPadding;
        endX = endX < startX ? startX : endX;
        //formatWidth = endX - startX;
        //formatWidth = endX;
       
        int startIndex = lineMeasurer.getPosition();

        int rightX = 0;

        if (segments.size() == 0)
        {
          rightX = (int)startX;
          //nextTabStop = nextTabStop;
        }
        else
        {
          rightX = oldSegment.rightX;
          nextTabStop = ParagraphUtil.getNextTabStop(text.getParagraph(), endX, rightX);
        }

        //float availableWidth = formatWidth - ParagraphUtil.getSegmentOffset(nextTabStop, rightX); // nextTabStop can be null here; and that's OK
        float availableWidth = endX - text.getParagraph().getLeftIndent() - ParagraphUtil.getSegmentOffset(nextTabStop, rightX); // nextTabStop can be null here; and that's OK
       
        // creating a text layout object for each tab segment
        TextLayout layout =
          lineMeasurer.nextLayout(
            availableWidth,
            tabIndexOrEndIndex,
            requireNextWord
            );
       
        if (layout != null)
        {
           AttributedString tmpText =
            new AttributedString(
              paragraph,
              startIndex,
              startIndex + layout.getCharacterCount()
              );
          
          if (isMinimizePrinterJobSize)
          {
            //eugene fix - start
            layout = new TextLayout(tmpText.getIterator(), getFontRenderContext());
            //eugene fix - end
          }
   
          if (
            text.getHorizontalAlignmentValue() == HorizontalAlignEnum.JUSTIFIED
            && lineMeasurer.getPosition() < paragraph.getEndIndex()
            )
          {
            layout = layout.getJustifiedLayout(availableWidth);
          }
         
          maxAscent = Math.max(maxAscent, layout.getAscent());
          maxDescent = Math.max(maxDescent, layout.getDescent());
          maxLeading = Math.max(maxLeading, layout.getLeading());

          //creating the current segment
          crtSegment = new TabSegment();
          crtSegment.layout = layout;
          crtSegment.as = tmpText;
          crtSegment.text = lastParagraphText.substring(startIndex, startIndex + layout.getCharacterCount());

          int leftX = ParagraphUtil.getLeftX(nextTabStop, layout.getAdvance()); // nextTabStop can be null here; and that's OK
          if (rightX > leftX)
          {
            crtSegment.leftX = rightX;
            crtSegment.rightX = (int)(rightX + layout.getAdvance());//FIXMETAB some rounding issues here
          }
          else
          {
            crtSegment.leftX = leftX;
            // we need this special tab stop based utility call because adding the advance to leftX causes rounding issues
            crtSegment.rightX = ParagraphUtil.getRightX(nextTabStop, layout.getAdvance()); // nextTabStop can be null here; and that's OK
          }

          segments.add(crtSegment);
        }
       
        requireNextWord = true;

        if (lineMeasurer.getPosition() == tabIndexOrEndIndex)
        {
          // the segment limit was a tab; going to the next tab
          currentTab++;
        }

        if (lineMeasurer.getPosition() == paragraph.getEndIndex())
        {
          // the segment limit was the paragraph end; line completed and next line should start at normal zero x offset
          lineComplete = true;
          nextTabStop = null;
        }
        else
        {
          // there is paragraph text remaining
          if (lineMeasurer.getPosition() == tabIndexOrEndIndex)
          {
            // the segment limit was a tab
            if (crtSegment.rightX >= ParagraphUtil.getLastTabStop(text.getParagraph(), endX).getPosition())
            {
              // current segment stretches out beyond the last tab stop; line complete
              lineComplete = true;
              // next line should should start at first tab stop indent
              nextTabStop = ParagraphUtil.getFirstTabStop(text.getParagraph(), endX);
            }
            else
            {
              //nothing; this leaves lineComplete=false
            }
          }
          else
          {
            // the segment did not fit entirely
            lineComplete = true;
            if (layout == null)
            {
              // nothing fitted; next line should start at first tab stop indent
              if (nextTabStop.getPosition() == ParagraphUtil.getFirstTabStop(text.getParagraph(), endX).getPosition())//FIXMETAB check based on segments.size()
              {
                // at second attempt we give up to avoid infinite loop
                nextTabStop = null;
                requireNextWord = false;
               
                //provide dummy maxFontSize because it is used for the line height of this empty line when attempting drawing below
                 AttributedString tmpText =
                  new AttributedString(
                    paragraph,
                    startIndex,
                    startIndex + 1
                    );
                 LineBreakMeasurer lbm = new LineBreakMeasurer(tmpText.getIterator(), getFontRenderContext());
                 TextLayout tlyt = lbm.nextLayout(100);
                maxAscent = tlyt.getAscent();
                maxDescent = tlyt.getDescent();
                maxLeading = tlyt.getLeading();
              }
              else
              {
                nextTabStop = ParagraphUtil.getFirstTabStop(text.getParagraph(), endX);
              }
            }
            else
            {
              // something fitted
              nextTabStop = null;
              requireNextWord = false;
            }
          }
        }

        oldSegment = crtSegment;
      }

      lineHeight = getLineHeight(lastParagraphStart == 0 && lines == 0, text.getParagraph(), maxLeading, maxAscent);// + maxDescent;
     
      if (lastParagraphStart == 0 && lines == 0)
      //if (lines == 0) //FIXMEPARA
      {
        lineHeight +=  text.getParagraph().getSpacingBefore().intValue();
      }

      if (drawPosY + lineHeight <= text.getTextHeight())
      {
        lines++;
       
        drawPosY += lineHeight;
       
        int lastRightX = (segments == null || segments.size() == 0 ? 0 : segments.get(segments.size() - 1).rightX);
       
        // now iterate through segments and draw their layouts
        for (segmentIndex = 0; segmentIndex < segments.size(); segmentIndex++)
        {
          TabSegment segment = segments.get(segmentIndex);
          TextLayout layout = segment.layout;

          switch (text.getHorizontalAlignmentValue())
          {
            case JUSTIFIED :
            {
              if (layout.isLeftToRight())
              {
                drawPosX = text.getParagraph().getLeftIndent() + segment.leftX;
              }
              else
              {
                drawPosX = (int)(endX - lastRightX + segment.leftX);
              }
 
              break;
            }
            case RIGHT ://FIXMETAB RTL writings
            {
              drawPosX = (int)(endX - lastRightX + segment.leftX);
              break;
            }
            case CENTER :
            {
              drawPosX = (int)((endX - lastRightX) / 2) + segment.leftX;
              break;
            }
            case LEFT :
            default :
            {
              drawPosX = text.getParagraph().getLeftIndent() + segment.leftX;
            }
          }

          /*   */
          draw();
        }
       
        drawPosY += maxDescent;
       
//        if (lineMeasurer.getPosition() == paragraph.getEndIndex()) //FIXMEPARA
//        {
//          drawPosY += text.getParagraph().getSpacingAfter().intValue();
//        }
      }
      else
      {
        isMaxHeightReached = true;
      }
    }
  }
 
  /**
   *
   */
  public abstract void draw();

  /**
   *
   */
  public static float getLineHeight(boolean isFirstLine, JRParagraph paragraph, float maxLeading, float maxAscent)
  {
    float lineHeight = 0;

    switch(paragraph.getLineSpacing())
    {
      case SINGLE:
      default :
      {
        lineHeight = maxLeading + 1f * maxAscent;
        break;
      }
      case ONE_AND_HALF:
      {
        if (isFirstLine)
        {
          lineHeight = maxLeading + 1f * maxAscent;
        }
        else
        {
          lineHeight = maxLeading + 1.5f * maxAscent;
        }
        break;
      }
      case DOUBLE:
      {
        if (isFirstLine)
        {
          lineHeight = maxLeading + 1f * maxAscent;
        }
        else
        {
          lineHeight = maxLeading + 2f * maxAscent;
        }
        break;
      }
      case PROPORTIONAL:
      {
        if (isFirstLine)
        {
          lineHeight = maxLeading + 1f * maxAscent;
        }
        else
        {
          lineHeight = maxLeading + paragraph.getLineSpacingSize().floatValue() * maxAscent;
        }
        break;
      }
      case AT_LEAST:
      {
        if (isFirstLine)
        {
          lineHeight = maxLeading + 1f * maxAscent;
        }
        else
        {
          lineHeight = Math.max(maxLeading + 1f * maxAscent, paragraph.getLineSpacingSize().floatValue());
        }
        break;
      }
      case FIXED:
      {
        if (isFirstLine)
        {
          lineHeight = maxLeading + 1f * maxAscent;
        }
        else
        {
          lineHeight = paragraph.getLineSpacingSize().floatValue();
        }
        break;
      }
    }
   
    return lineHeight;
  }

  /**
   *
   *
  public static float getLineHeight(JRParagraph paragraph, float lineSpacingFactor, int maxFontSize)
  {
    float lineHeight = 0;

    switch(paragraph.getLineSpacing())
    {
      case SINGLE:
      case ONE_AND_HALF:
      case DOUBLE:
      case PROPORTIONAL:
      {
        lineHeight = lineSpacingFactor * maxFontSize;
        break;
      }
      case AT_LEAST:
      {
        lineHeight = Math.max(lineSpacingFactor * maxFontSize, paragraph.getLineSpacingSize().floatValue());
        break;
      }
      case FIXED:
      {
        lineHeight = paragraph.getLineSpacingSize().floatValue();
        break;
      }
      default :
      {
        throw new JRRuntimeException("Invalid line space type: " + paragraph.getLineSpacing());
      }
    }
   
    return lineHeight;
  }


  /**
   *
   */
  public FontRenderContext getFontRenderContext()
  {
    return LINE_BREAK_FONT_RENDER_CONTEXT;
  }

}


/**
*
*/
class TabSegment
{
  public TextLayout layout;
  public AttributedString as;//FIXMETAB rename these
  public String text;
  public int leftX;
  public int rightX;
}
TOP

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

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.