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 */
041 package org.jfree.util;
042
043 import 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 */
051 public 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 }