⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 textparagraph.java

📁 Java的Web报表库
💻 JAVA
字号:
/**
 * ========================================
 * JFreeReport : a free Java report library
 * ========================================
 *
 * Project Info:  http://www.jfree.org/jfreereport/index.html
 * Project Lead:  Thomas Morgner;
 *
 * (C) Copyright 2000-2003, by Simba Management Limited and Contributors.
 *
 * This library 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 2.1 of the License, or (at your option) any later version.
 *
 * This library 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 this
 * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307, USA.
 *
 * ------------------
 * TextParagraph.java
 * ------------------
 * (C)opyright 2002, 2003, by Thomas Morgner and Contributors.
 *
 * Original Author:  Thomas Morgner;
 * Contributor(s):   David Gilbert (for Simba Management Limited);
 *
 * $Id: TextParagraph.java,v 1.24.2.1 2003/08/24 14:18:12 taqua Exp $
 *
 * Changes
 * -------
 *
 * 21-Jan-2003: BugFix: Breakline was inaccurate
 * 07-Feb-2003: Documentation
 */
package com.jrefinery.report.targets.base.content;

import java.awt.geom.Rectangle2D;
import java.text.BreakIterator;
import java.util.ArrayList;
import java.util.List;

import com.jrefinery.report.targets.base.layout.SizeCalculator;
import com.jrefinery.report.util.WordBreakIterator;

/**
 * A paragraph of an given text content. A paragraph consists of one or more
 * {@link TextLine}s.
 *
 * @author Thomas Morgner.
 */
public class TextParagraph extends ContentContainer
{
  /** A literal used for lines that get shortened by the linebreak implementation. */
  public static final String RESERVED_LITERAL = "..";

  /** The reserved size. */
  private float reservedSize = 0;

  /** The reserved size. */
  private float lineHeight = 0;

  /** The size calculator. */
  private SizeCalculator sizeCalculator;

  /**
   * Creates a new text paragraph using the specified size calculator.
   *
   * @param calc  the size calculator.
   * @param lineHeight the height of the lines contained in this paragraph.
   */
  public TextParagraph(final SizeCalculator calc, final float lineHeight)
  {
    super(new Rectangle2D.Float());
    this.sizeCalculator = calc;
    this.reservedSize = getSizeCalculator().getStringWidth(RESERVED_LITERAL, 0,
        RESERVED_LITERAL.length());
    this.lineHeight = lineHeight;
  }

  /**
   * Returns the size calculator.
   *
   * @return the size calculator.
   */
  private SizeCalculator getSizeCalculator()
  {
    return sizeCalculator;
  }

  /**
   * Sets the content.
   *
   * @param content  the content.
   * @param x the x coordinates for the bounds.
   * @param y the y coordinates for the bounds.
   * @param width the width of the bounds.
   * @param height the height of the bounds.
   */
  public void setContent
      (final String content, final float x, final float y, final float width, final float height)
  {
    if (content == null)
    {
      throw new NullPointerException("MaxBounds must not be null");
    }
    if (x < 0)
    {
      throw new IllegalArgumentException();
    }
    if (y < 0)
    {
      throw new IllegalArgumentException();
    }
    if (width < 0)
    {
      throw new IllegalArgumentException();
    }
    if (height < 0)
    {
      throw new IllegalArgumentException();
    }

    float usedHeight = 0;

    final int maxLines = (int) Math.floor(height / getSizeCalculator().getLineHeight());

    if (maxLines > 0)
    {
      final List l = breakLines(content, width, maxLines);
      /*
      if (l.size() > maxLines)
      {
        throw new IllegalStateException("MaxLines not working anymore");
      }
      */
      for (int i = 0; i < l.size(); i++)
      {
        // create Lines
        final String lineText = (String) l.get(i);
        final TextLine line = new TextLine(getSizeCalculator(), lineHeight);

/*
        // strict assertation ... is expensive and not enabled by default ...
        float tt = getSizeCalculator().getStringWidth(lineText, 0, lineText.length());
        if (tt >= width)
        {
          throw new IllegalStateException("LineBreak failed!:" + width + " -> " + tt);
        }
*/
        line.setContent(lineText, x, y + usedHeight, width, height - usedHeight);

        usedHeight += line.getHeight();
        if (line.getBounds().getHeight() > 0)
        {
          addContentPart(line);
        }
      }
    }
    setBounds(x, y, width, usedHeight);
  }

  /**
   * Breaks the text into multiple lines. The given string is broken either when a manual
   * linebreak is encountered or when the current line's rendered width exceeds the given limit.
   * If the text contains more than <code>maxLines</code> lines, all lines over the limit
   * are ignored.
   * <p>
   * If more than one line is expected or the strictmode is enabled and there are more lines
   * in the given text than space is available, the text is cut down to the given number of
   * lines and the RESERVED_LITERAL is appended to signal the cut down to the user.
   * <p>
   * The text is broken on word boundaries.
   *
   * @param mytext  the text to be broken down
   * @param width  the boundary on which the text is broken if no manual linebreak is encountered.
   * @param maxLines  the number of lines to be displayed. Must be at least 1
   *
   * @return a list of lines.
   */
  private List breakLines(final String mytext, final float width, final int maxLines)
  {
    if (width <= 0)
    {
      throw new IllegalArgumentException("Width must greater than 0, was " + width);
    }

    // a 0 maxLines is no longer allowed - to test the max size, ask the layoutmanager to
    // create a Max-Bounds and test that bound...
    if (maxLines < 1)
    {
      throw new IllegalArgumentException("MaxLines of <1 is not allowed");
    }

    // Reserve some space for the last line if there is more than one line to display.
    // If there is only one line, don't cut the line yet. Perhaps we intruduce the strict
    // mode later, but without any visual editing it would be cruel to any report designer.
    final WordBreakIterator breakit = new WordBreakIterator(mytext);
    final ArrayList returnLines = new ArrayList(5);

    int lineStartPos = 0;
    final int lineLength = mytext.length();
    if (lineLength == 0)
    {
      returnLines.add("");
      return returnLines;
    }

    while (lineStartPos < lineLength)
    {
      // the whole text section contains white spaces ... must be skipped ..
      // we can assume, that if the first character is a white space, then all
      // characters are whitespaces, as the word break iterator searches for
      // whitespace boundries ...
      /*
      while ((lineStartPos < lineLength) && (isWhitespace(mytext.charAt(lineStartPos))))
      {
        lineStartPos++;
      }
      */
      final boolean forceEnd = ((returnLines.size() + 1) == maxLines);
      final int nextPos = findNextBreak(mytext, lineStartPos, width, forceEnd, breakit);

      // the complete text is finished, noting more to do here.
      if (nextPos == BreakIterator.DONE)
      {
        final String addString = mytext.substring(lineStartPos);
        returnLines.add(addString);
        return returnLines;
      }

      if (forceEnd)
      {
        // it won't fit in, so break ...
        returnLines.add(appendReserveLit(mytext, lineStartPos, nextPos, width));
        return returnLines;
      }
      else
      {
        // End the line and restart for the next line ...
        final String addString = mytext.substring(lineStartPos, nextPos);
        returnLines.add(addString);
        lineStartPos = nextPos;
      }
    }
    return returnLines;
  }

  /**
   * Tests, whether the given character is a whitespace (but not a breakline).
   *
   * @param c the character that should be tested.
   * @return true, if this is a whitespace character, but not a
   * linebreak character, false otherwise.
   */
  /*
  private boolean isWhitespace(final char c)
  {
    if (c == '\n' || c == '\r')
    {
      return false;
    }
    else
    {
      return Character.isWhitespace(c);
    }
  }
  */

  /**
   * Locates the next linebreak for the given text.
   *
   * @param text the text that should be broken into lines
   * @param lineStart the position where the current line beginns
   * @param width the maximum width for a single line
   * @param forceEnd whether to enforce the end of the paragraph after that line
   * @param breakit the break iterator for the text
   * @return the most suitable position for an linebreak.
   */
  private int findNextBreak(final String text,
                            final int lineStart,
                            final float width,
                            final boolean forceEnd,
                            final WordBreakIterator breakit)
  {
    int startPos = lineStart;
    int endPos;
    float x = 0;
    // by default, we assume, that the line contains no break-positions,
    // like whitespaces etc.
    boolean enableCharBreak = true;

    // Break on WORD boundries ...
    // ---------------------------
    // check the complete line, break when the complete text is done or
    // the end of the line has been reached.
    while (((endPos = breakit.next()) != BreakIterator.DONE))
    {
      x += getSizeCalculator().getStringWidth(text, startPos, endPos);
      if (forceEnd)
      {
        // here is the last line, check whether the reserved literal will fit
        // in to the line, if not, then we have reached the end of the text field.
        if (x >= (width - reservedSize))
        {
          // return the last known linebreak pos...
          return startPos;
        }
      }
      else
      {
        if (x > width)
        {
          //when the first word of the line is too big then cut the word ...
          if (enableCharBreak)
          {
            while (getSizeCalculator().getStringWidth(text, startPos, endPos) > width)
            {
              endPos--;
            }
            breakit.setPosition(endPos);
            return endPos;
          }
          else
          {
            endPos = breakit.previous();
            return endPos;
          }
        }
      }

      // we found at least one break-boundry ...
      enableCharBreak = false;

      // the word is complete ... check whether the next word will fit on the line.
      startPos = endPos;
    }
    return BreakIterator.DONE;
  }


  /**
   * Add the reserve literal to the end of the string, but make sure that as much as
   * possible is printed in the line before the literal is finally added. So the last
   * word is not totally lost, maybe some characters can be printed ...
   *
   * @param base  the base string.
   * @param lineStart  the position of the first character in the line.
   * @param lastCheckedChar  the last character of the line, which is known to fit into the given
   *                         width.
   * @param width  the maximum width.
   *
   * @return a string with '..' appended.
   */
  private String appendReserveLit(final String base, final int lineStart, final int lastCheckedChar, final float width)
  {
    if (lastCheckedChar < 0)
    {
      throw new IllegalArgumentException("Start must not be negative");
    }
    if (width < 0)
    {
      throw new IllegalArgumentException("Width must not be negative");
    }
    if (lineStart < 0)
    {
      throw new IllegalArgumentException("LineStart must not be negative");
    }

    // check whether the complete line would fit into the given width
    final float toTheEnd = getSizeCalculator().getStringWidth(base, lineStart, base.length());
    if (toTheEnd <= width)
    {
      return base.substring(lineStart);
    }

    final String baseLine = base.substring(lineStart, lastCheckedChar);
    final float filler = width - (getSizeCalculator().getStringWidth(baseLine, 0, baseLine.length()))
        - reservedSize;

    final int maxFillerLength = base.length() - lastCheckedChar;
    for (int i = 1; i < maxFillerLength; i++)
    {
      final float fillerWidth = getSizeCalculator().getStringWidth(base, lastCheckedChar,
          lastCheckedChar + i);
      if (filler < fillerWidth)
      {
        return base.substring(lineStart, lastCheckedChar + i - 1) + RESERVED_LITERAL;
      }
    }
    return baseLine + RESERVED_LITERAL;
  }

  /**
   * Removes all whitespaces from the given String and replaces them with a space character.
   *
   * @param text  the string to process.
   *
   * @return  a string with all whitespace replaced by space characters.
   */
  protected String clearWhitespaces(final String text)
  {
    final char[] textdata = text.toCharArray();
    for (int i = 0; i < textdata.length; i++)
    {
      if (Character.isWhitespace(textdata[i]))
      {
        textdata[i] = ' ';
      }
    }
    return new String(textdata);
  }

}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -