    001/* ========================================================================
    002 * JCommon : a free general purpose class library for the Java(tm) platform
    003 * ========================================================================
    004 *
    005 * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
    006 *
    007 * Project Info:  http://www.jfree.org/jcommon/index.html
    008 *
    009 * This library is free software; you can redistribute it and/or modify it
    010 * under the terms of the GNU Lesser General Public License as published by
    011 * the Free Software Foundation; either version 2.1 of the License, or
    012 * (at your option) any later version.
    013 *
    014 * This library is distributed in the hope that it will be useful, but
    015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
    017 * License for more details.
    018 *
    019 * You should have received a copy of the GNU Lesser General Public
    020 * License along with this library; if not, write to the Free Software
    021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
    022 * USA.
    023 *
    024 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
    025 * in the United States and other countries.]
    026 *
    027 * ----------------------
    028 * LineBreakIterator.java
    029 * ----------------------
    030 * (C)opyright 2003, by Thomas Morgner and Contributors.
    031 *
    032 * Original Author:  Thomas Morgner;
    033 * Contributor(s):   David Gilbert (for Object Refinery Limited);
    034 *
    035 * $Id: LineBreakIterator.java,v 1.4 2005/11/03 09:55:26 mungady Exp $
    036 *
    037 * Changes
    038 * -------
    039 * 13-03-2003 : Initial version
    040 */
    041package org.jfree.util;
    042
    043import java.util.Iterator;
    044
    045/**
    046 * An iterator that breaks text into lines.
    047 * The result is equal to BufferedReader.readLine().
    048 *
    049 * @author Thomas Morgner
    050 */
    051public class LineBreakIterator implements Iterator
    052{
    053  /** A useful constant. */
    054  public static final int DONE = -1;
    055
    056  /** Storage for the text. */
    057  private char[] text;
    058
    059  /** The current position. */
    060  private int position;
    061
    062  /**
    063   * Default constructor.
    064   */
    065  public LineBreakIterator()
    066  {
    067    setText("");
    068  }
    069
    070  /**
    071   * Creates a new line break iterator.
    072   *
    073   * @param text the text to be broken up.
    074   */
    075  public LineBreakIterator(final String text)
    076  {
    077    setText(text);
    078  }
    079
    080  /**
    081   * Returns the position of the next break.
    082   *
    083   * @return A position.
    084   */
    085  public synchronized int nextPosition()
    086  {
    087    if (this.text == null)
    088    {
    089      return DONE;
    090    }
    091    if (this.position == DONE)
    092    {
    093      return DONE;
    094    }
    095
    096    // recognize \n, \r, \r\n
    097
    098    final int nChars = this.text.length;
    099    int nextChar = this.position;
    100
    101    for (;;)
    102    {
    103      if (nextChar >= nChars)
    104      {
    105        /* End of text reached */
    106        this.position = DONE;
    107        return DONE;
    108      }
    109
    110      boolean eol = false;
    111      char c = 0;
    112      int i;
    113
    114      // search the next line break, either \n or \r
    115      for (i = nextChar; i < nChars; i++)
    116      {
    117        c = this.text[i];
    118        if ((c == '\n') || (c == '\r'))
    119        {
    120          eol = true;
    121          break;
    122        }
    123      }
    124
    125      nextChar = i;
    126      if (eol)
    127      {
    128        nextChar++;
    129        if (c == '\r')
    130        {
    131          if ((nextChar < nChars) && (this.text[nextChar] == '\n'))
    132          {
    133            nextChar++;
    134          }
    135        }
    136        this.position = nextChar;
    137        return (this.position);
    138      }
    139    }
    140  }
    141
    142  /**
    143   * Same like next(), but returns the End-Of-Text as
    144   * if there was a linebreak added (Reader.readLine() compatible)
    145   *
    146   * @return The next position.
    147   */
    148  public int nextWithEnd()
    149  {
    150    final int pos = this.position;
    151    if (pos == DONE)
    152    {
    153      return DONE;
    154    }
    155    if (pos == this.text.length)
    156    {
    157      this.position = DONE;
    158      return DONE;
    159    }
    160    final int retval = nextPosition();
    161    if (retval == DONE)
    162    {
    163      return this.text.length;
    164    }
    165    return retval;
    166  }
    167
    168  /**
    169   * Returns the text to be broken up.
    170   *
    171   * @return The text.
    172   */
    173  public String getText()
    174  {
    175    return new String(this.text);
    176  }
    177
    178  /**
    179   * Sets the text to be broken up.
    180   *
    181   * @param text  the text.
    182   */
    183  public void setText(final String text)
    184  {
    185    this.position = 0;
    186    this.text = text.toCharArray();
    187  }
    188
    189  /**
    190   * Returns <tt>true</tt> if the iteration has more elements. (In other
    191   * words, returns <tt>true</tt> if <tt>next</tt> would return an element
    192   * rather than throwing an exception.)
    193   *
    194   * @return <tt>true</tt> if the iterator has more elements.
    195   */
    196  public boolean hasNext()
    197  {
    198    return (this.position != DONE);
    199  }
    200
    201  /**
    202   * Returns the next element in the iteration.
    203   *
    204   * @return the next element in the iteration.
    205   */
    206  public Object next()
    207  {
    208    if (this.position == DONE)
    209    {
    210      // allready at the end ...
    211      return null;
    212    }
    213
    214    final int lastFound = this.position;
    215    int pos = nextWithEnd();
    216    if (pos == DONE)
    217    {
    218      // the end of the text has been reached ...
    219      return new String(this.text, lastFound, this.text.length - lastFound);
    220    }
    221
    222    // step one char back
    223    if (pos > 0)
    224    {
    225      final int end = lastFound;
    226      for (; ((pos) > end) && ((this.text[pos - 1] == '\n') || this.text[pos - 1] == '\r'); pos--)
    227      {
    228        // search the end of the current linebreak sequence ..
    229      }
    230    }
    231    //System.out.println ("text: " + new String (text));
    232    //System.out.println ("pos: " + pos + " lastFound: " + lastFound);
    233    return new String(this.text, lastFound, pos - lastFound);
    234  }
    235
    236  /**
    237   *
    238   * Removes from the underlying collection the last element returned by the
    239   * iterator (optional operation).  This method can be called only once per
    240   * call to <tt>next</tt>.  The behavior of an iterator is unspecified if
    241   * the underlying collection is modified while the iteration is in
    242   * progress in any way other than by calling this method.
    243   *
    244   * @exception UnsupportedOperationException if the <tt>remove</tt>
    245   *    operation is not supported by this Iterator.
    246   * @exception IllegalStateException if the <tt>next</tt> method has not
    247   *    yet been called, or the <tt>remove</tt> method has already
    248   *    been called after the last call to the <tt>next</tt>
    249   *    method.
    250   */
    251  public void remove()
    252  {
    253      throw new UnsupportedOperationException("This iterator is read-only.");
    254  }
    255}