1/*
2 * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25package javax.swing.text;
26
27import java.text.CharacterIterator;
28
29/**
30 * A segment of a character array representing a fragment
31 * of text.  It should be treated as immutable even though
32 * the array is directly accessible.  This gives fast access
33 * to fragments of text without the overhead of copying
34 * around characters.  This is effectively an unprotected
35 * String.
36 * <p>
37 * The Segment implements the java.text.CharacterIterator
38 * interface to support use with the i18n support without
39 * copying text into a string.
40 *
41 * @author  Timothy Prinzing
42 */
43public class Segment implements Cloneable, CharacterIterator, CharSequence {
44
45    /**
46     * This is the array containing the text of
47     * interest.  This array should never be modified;
48     * it is available only for efficiency.
49     */
50    public char[] array;
51
52    /**
53     * This is the offset into the array that
54     * the desired text begins.
55     */
56    public int offset;
57
58    /**
59     * This is the number of array elements that
60     * make up the text of interest.
61     */
62    public int count;
63
64    private boolean partialReturn;
65
66    /**
67     * Creates a new segment.
68     */
69    public Segment() {
70        this(null, 0, 0);
71    }
72
73    /**
74     * Creates a new segment referring to an existing array.
75     *
76     * @param array the array to refer to
77     * @param offset the offset into the array
78     * @param count the number of characters
79     */
80    public Segment(char[] array, int offset, int count) {
81        this.array = array;
82        this.offset = offset;
83        this.count = count;
84        partialReturn = false;
85    }
86
87    /**
88     * Flag to indicate that partial returns are valid.  If the flag is true,
89     * an implementation of the interface method Document.getText(position,length,Segment)
90     * should return as much text as possible without making a copy.  The default
91     * state of the flag is false which will cause Document.getText(position,length,Segment)
92     * to provide the same return behavior it always had, which may or may not
93     * make a copy of the text depending upon the request.
94     *
95     * @param p whether or not partial returns are valid.
96     * @since 1.4
97     */
98    public void setPartialReturn(boolean p) {
99        partialReturn = p;
100    }
101
102    /**
103     * Flag to indicate that partial returns are valid.
104     *
105     * @return whether or not partial returns are valid.
106     * @since 1.4
107     */
108    public boolean isPartialReturn() {
109        return partialReturn;
110    }
111
112    /**
113     * Converts a segment into a String.
114     *
115     * @return the string
116     */
117    public String toString() {
118        if (array != null) {
119            return new String(array, offset, count);
120        }
121        return "";
122    }
123
124    // --- CharacterIterator methods -------------------------------------
125
126    /**
127     * Sets the position to getBeginIndex() and returns the character at that
128     * position.
129     * @return the first character in the text, or DONE if the text is empty
130     * @see #getBeginIndex
131     * @since 1.3
132     */
133    public char first() {
134        pos = offset;
135        if (count != 0) {
136            return array[pos];
137        }
138        return DONE;
139    }
140
141    /**
142     * Sets the position to getEndIndex()-1 (getEndIndex() if the text is empty)
143     * and returns the character at that position.
144     * @return the last character in the text, or DONE if the text is empty
145     * @see #getEndIndex
146     * @since 1.3
147     */
148    public char last() {
149        pos = offset + count;
150        if (count != 0) {
151            pos -= 1;
152            return array[pos];
153        }
154        return DONE;
155    }
156
157    /**
158     * Gets the character at the current position (as returned by getIndex()).
159     * @return the character at the current position or DONE if the current
160     * position is off the end of the text.
161     * @see #getIndex
162     * @since 1.3
163     */
164    public char current() {
165        if (count != 0 && pos < offset + count) {
166            return array[pos];
167        }
168        return DONE;
169    }
170
171    /**
172     * Increments the iterator's index by one and returns the character
173     * at the new index.  If the resulting index is greater or equal
174     * to getEndIndex(), the current index is reset to getEndIndex() and
175     * a value of DONE is returned.
176     * @return the character at the new position or DONE if the new
177     * position is off the end of the text range.
178     * @since 1.3
179     */
180    public char next() {
181        pos += 1;
182        int end = offset + count;
183        if (pos >= end) {
184            pos = end;
185            return DONE;
186        }
187        return current();
188    }
189
190    /**
191     * Decrements the iterator's index by one and returns the character
192     * at the new index. If the current index is getBeginIndex(), the index
193     * remains at getBeginIndex() and a value of DONE is returned.
194     * @return the character at the new position or DONE if the current
195     * position is equal to getBeginIndex().
196     * @since 1.3
197     */
198    public char previous() {
199        if (pos == offset) {
200            return DONE;
201        }
202        pos -= 1;
203        return current();
204    }
205
206    /**
207     * Sets the position to the specified position in the text and returns that
208     * character.
209     * @param position the position within the text.  Valid values range from
210     * getBeginIndex() to getEndIndex().  An IllegalArgumentException is thrown
211     * if an invalid value is supplied.
212     * @return the character at the specified position or DONE if the specified position is equal to getEndIndex()
213     * @since 1.3
214     */
215    public char setIndex(int position) {
216        int end = offset + count;
217        if ((position < offset) || (position > end)) {
218            throw new IllegalArgumentException("bad position: " + position);
219        }
220        pos = position;
221        if ((pos != end) && (count != 0)) {
222            return array[pos];
223        }
224        return DONE;
225    }
226
227    /**
228     * Returns the start index of the text.
229     * @return the index at which the text begins.
230     * @since 1.3
231     */
232    public int getBeginIndex() {
233        return offset;
234    }
235
236    /**
237     * Returns the end index of the text.  This index is the index of the first
238     * character following the end of the text.
239     * @return the index after the last character in the text
240     * @since 1.3
241     */
242    public int getEndIndex() {
243        return offset + count;
244    }
245
246    /**
247     * Returns the current index.
248     * @return the current index.
249     * @since 1.3
250     */
251    public int getIndex() {
252        return pos;
253    }
254
255    // --- CharSequence methods -------------------------------------
256
257    /**
258     * {@inheritDoc}
259     * @since 1.6
260     */
261    public char charAt(int index) {
262        if (index < 0
263            || index >= count) {
264            throw new StringIndexOutOfBoundsException(index);
265        }
266        return array[offset + index];
267    }
268
269    /**
270     * {@inheritDoc}
271     * @since 1.6
272     */
273    public int length() {
274        return count;
275    }
276
277    /**
278     * {@inheritDoc}
279     * @since 1.6
280     */
281    public CharSequence subSequence(int start, int end) {
282        if (start < 0) {
283            throw new StringIndexOutOfBoundsException(start);
284        }
285        if (end > count) {
286            throw new StringIndexOutOfBoundsException(end);
287        }
288        if (start > end) {
289            throw new StringIndexOutOfBoundsException(end - start);
290        }
291        Segment segment = new Segment();
292        segment.array = this.array;
293        segment.offset = this.offset + start;
294        segment.count = end - start;
295        return segment;
296    }
297
298    /**
299     * Creates a shallow copy.
300     *
301     * @return the copy
302     */
303    public Object clone() {
304        Object o;
305        try {
306            o = super.clone();
307        } catch (CloneNotSupportedException cnse) {
308            o = null;
309        }
310        return o;
311    }
312
313    private int pos;
314
315
316}
317