]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-4_2_1-src/src/com/ibm/richtext/styledtext/StyledText.java
icu4jsrc
[Dictionary.git] / jars / icu4j-4_2_1-src / src / com / ibm / richtext / styledtext / StyledText.java
1 /*\r
2  * (C) Copyright IBM Corp. 1998-2004.  All Rights Reserved.\r
3  *\r
4  * The program is provided "as is" without any warranty express or\r
5  * implied, including the warranty of non-infringement and the implied\r
6  * warranties of merchantibility and fitness for a particular purpose.\r
7  * IBM will not be liable for any damages suffered by you as a result\r
8  * of using the Program. In no event will IBM be liable for any\r
9  * special, indirect or consequential damages or lost profits even if\r
10  * IBM has been advised of the possibility of their occurrence. IBM\r
11  * will not be liable for any third party claims against you.\r
12  */\r
13 package com.ibm.richtext.styledtext;\r
14 \r
15 import com.ibm.richtext.textlayout.attributes.AttributeMap;\r
16 \r
17 import java.io.Externalizable;\r
18 import java.io.ObjectInput;\r
19 import java.io.ObjectOutput;\r
20 import java.io.IOException;\r
21 import java.text.CharacterIterator;\r
22 \r
23 /**\r
24  * This class is an implementation of MText, a modifyable, styled text\r
25  * storage model.  Additionally, it supports persistance through the\r
26  * Externalizable interface.\r
27  * @see MText\r
28  */\r
29 \r
30 /*\r
31     10/28/96 {jf} - split the character and paragraph style access and setter function around...\r
32             just to keep things interesting.\r
33     8/7/96 {jf} - moved paragraph break implementation from AbstractText into Style text.\r
34             - added countStyles, getStyles, and ReplaceStyles implementation.\r
35 \r
36     8/14/96 sfb  eliminated StyleSheetIterator\r
37 \r
38     8/29/96 {jbr} changed iter-based replace method - doesn't call at() unless it is safe to do so\r
39             Also, added checkStartAndLimit for debugging\r
40 \r
41     7/31/98 Switched from Style to AttributeMap\r
42 \r
43 */\r
44 \r
45 public final class StyledText extends MText implements Externalizable\r
46 {\r
47     static final String COPYRIGHT =\r
48                 "(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";\r
49     private static final int CURRENT_VERSION = 1;\r
50     private static final long serialVersionUID = 22356934;\r
51 \r
52     /* unicode storage */\r
53     private MCharBuffer         fCharBuffer;\r
54     /* character style storage */\r
55     private MStyleBuffer        fStyleBuffer;\r
56     /* paragraph style storage */\r
57     private MParagraphBuffer    fParagraphBuffer;\r
58 \r
59     private transient int fTimeStamp = 0;\r
60     private transient int[] fDamagedRange = { Integer.MAX_VALUE,\r
61                                               Integer.MIN_VALUE };\r
62 \r
63     private static class ForceModifier extends StyleModifier {\r
64 \r
65         private AttributeMap fStyle = AttributeMap.EMPTY_ATTRIBUTE_MAP;\r
66 \r
67         void setStyle(AttributeMap style) {\r
68 \r
69             fStyle = style;\r
70         }\r
71 \r
72         public AttributeMap modifyStyle(AttributeMap style) {\r
73 \r
74             return fStyle;\r
75         }\r
76     }\r
77 \r
78     // Keep this around foruse in replaceCharStylesWith.  OK since\r
79     // this class isn't threadsafe anyway.\r
80     private transient ForceModifier forceModifier = null;\r
81 \r
82     //======================================================\r
83     // CONSTRUCTORS\r
84     //======================================================\r
85     /**\r
86      * Create an empty text object.\r
87      */\r
88     public StyledText()\r
89     {\r
90         this(0);\r
91     }\r
92 \r
93     /**\r
94      * Create an empty text object ready to hold at least capacity chars.\r
95      * @param capacity the minimum capacity of the internal text buffer\r
96      */\r
97     public StyledText(int capacity)\r
98     {\r
99         fCharBuffer         = capacity>0? new CharBuffer(capacity) : new CharBuffer();\r
100         fStyleBuffer        = new StyleBuffer(this, AttributeMap.EMPTY_ATTRIBUTE_MAP);\r
101         fParagraphBuffer    = new ParagraphBuffer(fCharBuffer);\r
102     }\r
103 \r
104     /**\r
105      * Create a text object with the characters in the string,\r
106      * in the given style.\r
107      * @param string the initial contents\r
108      * @param initialStyle the style of the initial text\r
109      */\r
110     public StyledText(String string, AttributeMap initialStyle)\r
111     {\r
112         fCharBuffer = new CharBuffer(string.length());\r
113         fCharBuffer.replace(0, 0, string, 0, string.length());\r
114 \r
115         fStyleBuffer = new StyleBuffer(this, initialStyle);\r
116         fParagraphBuffer = new ParagraphBuffer(fCharBuffer);\r
117     }\r
118 \r
119     /**\r
120      * Create a text object from the given source.\r
121      * @param source the text to copy\r
122      */\r
123     public StyledText(MConstText source) {\r
124         this();\r
125         append(source);\r
126     }\r
127     \r
128     /**\r
129      * Create a text object from a subrange of the given source.\r
130      * @param source the text to copy from\r
131      * @param srcStart the index of the first character to copy\r
132      * @param srcLimit the index after the last character to copy\r
133      */\r
134     public StyledText(MConstText source, int srcStart, int srcLimit) {\r
135         this();\r
136         replace(0, 0, source, srcStart, srcLimit);\r
137     }\r
138 \r
139     public void writeExternal(ObjectOutput out) throws IOException {\r
140 \r
141         out.writeInt(CURRENT_VERSION);\r
142         out.writeObject(fCharBuffer);\r
143         out.writeObject(fStyleBuffer);\r
144         out.writeObject(fParagraphBuffer);\r
145     }\r
146 \r
147     public void readExternal(ObjectInput in) throws IOException,\r
148                                             ClassNotFoundException {\r
149 \r
150         int version = in.readInt();\r
151         if (version != CURRENT_VERSION) {\r
152             throw new IOException("Invalid version of StyledText: " + version);\r
153         }\r
154         fCharBuffer = (MCharBuffer) in.readObject();\r
155         fStyleBuffer = (MStyleBuffer) in.readObject();\r
156         fParagraphBuffer = (MParagraphBuffer) in.readObject();\r
157 \r
158         resetDamagedRange();\r
159     }\r
160 \r
161     //======================================================\r
162     // MConstText INTERFACES\r
163     //======================================================\r
164 \r
165     //--------------------------------------------------------\r
166     // character access\r
167     //--------------------------------------------------------\r
168 /**\r
169 * Return the character at offset <code>pos</code>.\r
170 * @param pos a valid offset into the text\r
171 * @return the character at offset <code>pos</code>\r
172 */\r
173     public char at(int pos)\r
174     {\r
175         return fCharBuffer.at(pos);\r
176     }\r
177 \r
178 /**\r
179 * Copy the characters in the range [<code>start</code>, <code>limit</code>)\r
180 * into the array <code>dst</code>, beginning at <code>dstStart</code>.\r
181 * @param start offset of first character which will be copied into the array\r
182 * @param limit offset immediately after the last character which will be copied into the array\r
183 * @param dst array in which to copy characters.  The length of <code>dst</code> must be at least\r
184 * (<code>dstStart + limit - start</code>).\r
185 */\r
186     public void extractChars(int start, int limit, char[] dst, int dstStart)\r
187     {\r
188         fCharBuffer.at(start, limit, dst, dstStart);\r
189     }\r
190 \r
191     //-------------------------------------------------------\r
192     // text model creation\r
193     //-------------------------------------------------------\r
194 /**\r
195 * Create an MConstText containing the characters and styles in the range\r
196 * [<code>start</code>, <code>limit</code>).\r
197 * @param start offset of first character in the new text\r
198 * @param limit offset immediately after the last character in the new text\r
199 * @return an MConstText object containing the characters and styles in the given range\r
200 */\r
201     public MConstText extract(int start, int limit)\r
202     {\r
203         return extractWritable(start, limit);\r
204     }\r
205 \r
206 /**\r
207 * Create an MText containing the characters and styles in the range\r
208 * [<code>start</code>, <code>limit</code>).\r
209 * @param start offset of first character in the new text\r
210 * @param limit offset immediately after the last character in the new text\r
211 * @return an MConstText object containing the characters and styles in the given range\r
212 */\r
213     public MText extractWritable(int start, int limit)\r
214     {\r
215         MText text = new StyledText();\r
216         text.replace(0, 0, this, start, limit);\r
217         text.resetDamagedRange();\r
218         return text;\r
219     }\r
220 \r
221     //--------------------------------------------------------\r
222     // size/capacity\r
223     //--------------------------------------------------------\r
224 /**\r
225 * Return the length of the MConstText object.  The length is the number of characters in the text.\r
226 * @return the length of the MConstText object\r
227 */\r
228     public int length()\r
229     {\r
230         return fCharBuffer.length();\r
231     }\r
232 \r
233 /**\r
234 * Create a <code>CharacterIterator</code> over the range [<code>start</code>, <code>limit</code>).\r
235 * @param start the beginning of the iterator's range\r
236 * @param limit the limit of the iterator's range\r
237 * @return a valid <code>CharacterIterator</code> over the specified range\r
238 * @see java.text.CharacterIterator\r
239 */\r
240     public CharacterIterator createCharacterIterator(int start, int limit)\r
241     {\r
242         return fCharBuffer.createCharacterIterator(start, limit);\r
243     }\r
244 \r
245     //--------------------------------------------------------\r
246     // character styles\r
247     //--------------------------------------------------------\r
248 \r
249 /**\r
250 * Return the index of the first character in the character style run\r
251 * containing pos.  All characters in a style run have the same character\r
252 * style.\r
253 * @return the style at offset <code>pos</code>\r
254 */\r
255     public int characterStyleStart(int pos) {\r
256 \r
257         checkPos(pos, LESS_THAN_LENGTH);\r
258         return fStyleBuffer.styleStart(pos);\r
259     }\r
260 \r
261 /**\r
262 * Return the index after the last character in the character style run\r
263 * containing pos.  All characters in a style run have the same character\r
264 * style.\r
265 * @return the style at offset <code>pos</code>\r
266 */\r
267     public int characterStyleLimit(int pos) {\r
268 \r
269         checkPos(pos, NOT_GREATER_THAN_LENGTH);\r
270         return fStyleBuffer.styleLimit(pos);\r
271     }\r
272 \r
273 /**\r
274 * Return the style applied to the character at offset <code>pos</code>.\r
275 * @param pos a valid offset into the text\r
276 * @return the style at offset <code>pos</code>\r
277 */\r
278     public AttributeMap characterStyleAt(int pos)\r
279     {\r
280         checkPos(pos, NOT_GREATER_THAN_LENGTH);\r
281         return fStyleBuffer.styleAt(pos);\r
282     }\r
283 \r
284     //--------------------------------------------------------\r
285     // paragraph boundaries and styles\r
286     //--------------------------------------------------------\r
287 /**\r
288 * Return the start of the paragraph containing the character at offset <code>pos</code>.\r
289 * @param pos a valid offset into the text\r
290 * @return the start of the paragraph containing the character at offset <code>pos</code>\r
291 */\r
292     public int paragraphStart(int pos)\r
293     {\r
294         checkPos(pos, NOT_GREATER_THAN_LENGTH);\r
295         return fParagraphBuffer.paragraphStart(pos);\r
296     }\r
297 \r
298 /**\r
299 * Return the limit of the paragraph containing the character at offset <code>pos</code>.\r
300 * @param pos a valid offset into the text\r
301 * @return the limit of the paragraph containing the character at offset <code>pos</code>\r
302 */\r
303     public int paragraphLimit(int pos)\r
304     {\r
305         checkPos(pos, NOT_GREATER_THAN_LENGTH);\r
306         return fParagraphBuffer.paragraphLimit(pos);\r
307     }\r
308 \r
309 /**\r
310 * Return the paragraph style applied to the paragraph containing offset <code>pos</code>.\r
311 * @param pos a valid offset into the text\r
312 * @return the paragraph style in effect at <code>pos</code>\r
313 */\r
314     public AttributeMap paragraphStyleAt(int pos)\r
315     {\r
316         checkPos(pos, NOT_GREATER_THAN_LENGTH);\r
317         return fParagraphBuffer.paragraphStyleAt(pos);\r
318     }\r
319 \r
320 /**\r
321 * Return the current time stamp.  The time stamp is\r
322 * incremented whenever the contents of the MConstText changes.\r
323 * @return the current paragraph style time stamp\r
324 */\r
325     public int getTimeStamp() {\r
326 \r
327         return fTimeStamp;\r
328     }\r
329 \r
330     //======================================================\r
331     // MText INTERFACES\r
332     //======================================================\r
333     //--------------------------------------------------------\r
334     // character modfication functions\r
335     //--------------------------------------------------------\r
336 \r
337     private void updateDamagedRange(int deleteStart,\r
338                                     int deleteLimit,\r
339                                     int insertLength) {\r
340 \r
341         fDamagedRange[0] = Math.min(fDamagedRange[0], deleteStart);\r
342 \r
343         if (fDamagedRange[1] >= deleteLimit) {\r
344             int lengthChange = insertLength - (deleteLimit-deleteStart);\r
345             fDamagedRange[1] += lengthChange;\r
346         }\r
347         else {\r
348             fDamagedRange[1] = deleteStart + insertLength;\r
349         }\r
350     }\r
351 \r
352 /**\r
353 * Replace the characters and styles in the range [<code>start</code>, <code>limit</code>) with the characters\r
354 * and styles in <code>srcText</code> in the range [<code>srcStart</code>, <code>srcLimit</code>).  <code>srcText</code> is not\r
355 * modified.\r
356 * @param start the offset at which the replace operation begins\r
357 * @param limit the offset at which the replace operation ends.  The character and style at\r
358 * <code>limit</code> is not modified.\r
359 * @param text the source for the new characters and styles\r
360 * @param srcStart the offset into <code>srcText</code> where new characters and styles will be obtained\r
361 * @param srcLimit the offset into <code>srcText</code> where the new characters and styles end\r
362 */\r
363     public void replace(int start, int limit, MConstText text, int srcStart, int srcLimit)\r
364     {\r
365         if (text == this) {\r
366             text = new StyledText(text);\r
367         }\r
368 \r
369         if (start == limit && srcStart == srcLimit) {\r
370             return;\r
371         }\r
372 \r
373         checkStartLimit(start, limit);\r
374 \r
375         updateDamagedRange(start, limit, srcLimit-srcStart);\r
376 \r
377         fCharBuffer.replace(start, limit, text, srcStart, srcLimit);\r
378         fStyleBuffer.replace(start, limit, text, srcStart, srcLimit);\r
379         fParagraphBuffer.replace(start, limit, text, srcStart, srcLimit, fDamagedRange);\r
380         fTimeStamp += 1;\r
381     }\r
382 \r
383 /**\r
384 * Replace the characters and styles in the range [<code>start</code>, <code>limit</code>) with the characters\r
385 * and styles in <code>srcText</code>.  <code>srcText</code> is not\r
386 * modified.\r
387 * @param start the offset at which the replace operation begins\r
388 * @param limit the offset at which the replace operation ends.  The character and style at\r
389 * <code>limit</code> is not modified.\r
390 * @param text the source for the new characters and styles\r
391 */\r
392     public void replace(int start, int limit, MConstText text) {\r
393 \r
394         replace(start, limit, text, 0, text.length());\r
395     }\r
396 \r
397 /**\r
398 * Replace the characters in the range [<code>start</code>, <code>limit</code>) with the characters\r
399 * in <code>srcChars</code> in the range [<code>srcStart</code>, <code>srcLimit</code>).  New characters take on the style\r
400 * <code>charsStyle</code>.\r
401 * <code>srcChars</code> is not modified.\r
402 * @param start the offset at which the replace operation begins\r
403 * @param limit the offset at which the replace operation ends.  The character at\r
404 * <code>limit</code> is not modified.\r
405 * @param srcChars the source for the new characters\r
406 * @param srcStart the offset into <code>srcChars</code> where new characters will be obtained\r
407 * @param srcLimit the offset into <code>srcChars</code> where the new characters end\r
408 * @param charsStyle the style of the new characters\r
409 */\r
410     public void replace(int start, int limit, char[] srcChars, int srcStart, int srcLimit, AttributeMap charsStyle)\r
411     {\r
412         checkStartLimit(start, limit);\r
413 \r
414         if (start == limit && srcStart == srcLimit) {\r
415             return;\r
416         }\r
417 \r
418         updateDamagedRange(start, limit, srcLimit-srcStart);\r
419 \r
420         fCharBuffer.replace(start, limit, srcChars, srcStart, srcLimit);\r
421 \r
422         replaceCharStylesWith(start, limit, start + (srcLimit-srcStart), charsStyle);\r
423 \r
424         fParagraphBuffer.deleteText(start, limit, fDamagedRange);\r
425         fParagraphBuffer.insertText(start, srcChars, srcStart, srcLimit);\r
426 \r
427         fTimeStamp += 1;\r
428     }\r
429 \r
430     private void replaceCharStylesWith(int start, int oldLimit, int newLimit, AttributeMap style) {\r
431 \r
432         if (start < oldLimit) {\r
433             fStyleBuffer.deleteText(start, oldLimit);\r
434         }\r
435         if (start < newLimit) {\r
436             if (forceModifier == null) {\r
437                 forceModifier = new ForceModifier();\r
438             }\r
439             forceModifier.setStyle(style);\r
440             fStyleBuffer.insertText(start, newLimit);\r
441             fStyleBuffer.modifyStyles(start, newLimit, forceModifier, null);\r
442         }\r
443     }\r
444 \r
445 /**\r
446 * Replace the characters in the range [<code>start</code>, <code>limit</code>) with the character <code>srcChar</code>.\r
447 * The new character takes on the style <code>charStyle</code>\r
448 * @param start the offset at which the replace operation begins\r
449 * @param limit the offset at which the replace operation ends.  The character at\r
450 * <code>limit</code> is not modified.\r
451 * @param srcChar the new character\r
452 * @param charStyle the style of the new character\r
453 */\r
454     public void replace(int start, int limit, char srcChar, AttributeMap charStyle)\r
455     {\r
456         checkStartLimit(start, limit);\r
457 \r
458         updateDamagedRange(start, limit, 1);\r
459 \r
460         fCharBuffer.replace(start, limit, srcChar);\r
461 \r
462         replaceCharStylesWith(start, limit, start + 1, charStyle);\r
463 \r
464         if (start < limit) {\r
465             fParagraphBuffer.deleteText(start, limit, fDamagedRange);\r
466         }\r
467 \r
468         fParagraphBuffer.insertText(start, srcChar);\r
469 \r
470         fTimeStamp += 1;\r
471     }\r
472 \r
473 /**\r
474 * Replace the entire contents of this MText (both characters and styles) with\r
475 * the contents of <code>srcText</code>.\r
476 * @param srcText the source for the new characters and styles\r
477 */\r
478     public void replaceAll(MConstText srcText)\r
479     {\r
480         replace(0, length(), srcText, 0, srcText.length());\r
481     }\r
482 \r
483 /**\r
484 * Insert the contents of <code>srcText</code> (both characters and styles) into this\r
485 * MText at the position specified by <code>pos</code>.\r
486 * @param pos The character offset where the new text is to be inserted.\r
487 * @param srcText The text to insert.\r
488 */\r
489     public void insert(int pos, MConstText srcText)\r
490     {\r
491         replace(pos, pos, srcText, 0, srcText.length());\r
492     }\r
493 \r
494 /**\r
495 * Append the contents of <code>srcText</code> (both characters and styles) to the\r
496 * end of this MText.\r
497 * @param srcText The text to append.\r
498 */\r
499     public void append(MConstText srcText)\r
500     {\r
501         replace(length(), length(), srcText, 0, srcText.length());\r
502     }\r
503 \r
504 /**\r
505 * Delete the specified range of characters (and styles).\r
506 * @param start Offset of the first character to delete.\r
507 * @param limit Offset of the first character after the range to delete.\r
508 */\r
509     public void remove(int start, int limit)\r
510     {\r
511         replace(start, limit, (char[])null, 0, 0, AttributeMap.EMPTY_ATTRIBUTE_MAP);\r
512     }\r
513 \r
514 /**\r
515 * Delete all characters and styles.  Always increments time stamp.\r
516 */\r
517     public void remove()\r
518     {\r
519         // rather than going through replace(), just reinitialize the StyledText,\r
520         // letting the old data structures fall on the floor\r
521         fCharBuffer = new CharBuffer();\r
522         fStyleBuffer = new StyleBuffer(this, AttributeMap.EMPTY_ATTRIBUTE_MAP);\r
523         fParagraphBuffer = new ParagraphBuffer(fCharBuffer);\r
524         fTimeStamp += 1;\r
525         fDamagedRange[0] = fDamagedRange[1] = 0;\r
526     }\r
527 \r
528     //--------------------------------------------------------\r
529     // storage management\r
530     //--------------------------------------------------------\r
531 \r
532 /**\r
533 * Minimize the amount of memory used by the MText object.\r
534 */\r
535     public void compress() {\r
536 \r
537         fCharBuffer.compress();\r
538         fStyleBuffer.compress();\r
539         fParagraphBuffer.compress();\r
540     }\r
541 \r
542     //--------------------------------------------------------\r
543     // style modification\r
544     //--------------------------------------------------------\r
545 \r
546 /**\r
547 * Set the style of all characters in the MText object to\r
548 * <code>AttributeMap.EMPTY_ATTRIBUTE_MAP</code>.\r
549 */\r
550     public void removeCharacterStyles() {\r
551 \r
552         fStyleBuffer = new StyleBuffer(this, AttributeMap.EMPTY_ATTRIBUTE_MAP);\r
553         fTimeStamp += 1;\r
554         fDamagedRange[0] = 0;\r
555         fDamagedRange[1] = length();\r
556     }\r
557 \r
558 /**\r
559 * Invoke the given modifier on all character styles from start to limit.\r
560 * @param modifier the modifier to apply to the range.\r
561 * @param start the start of the range of text to modify.\r
562 * @param limit the limit of the range of text to modify.\r
563 */\r
564     public void modifyCharacterStyles(int start, int limit, StyleModifier modifier) {\r
565 \r
566         checkStartLimit(start, limit);\r
567         boolean modified = fStyleBuffer.modifyStyles(start,\r
568                                                      limit,\r
569                                                      modifier,\r
570                                                      fDamagedRange);\r
571         if (modified) {\r
572             fTimeStamp += 1;\r
573         }\r
574     }\r
575 \r
576 /**\r
577 * Invoke the given modifier on all paragraph styles in paragraphs\r
578 * containing characters in the range [start, limit).\r
579 * @param modifier the modifier to apply to the range.\r
580 * @param start the start of the range of text to modify.\r
581 * @param limit the limit of the range of text to modify.\r
582 */\r
583     public void modifyParagraphStyles(int start, int limit, StyleModifier modifier) {\r
584 \r
585         checkStartLimit(start, limit);\r
586         boolean modified = fParagraphBuffer.modifyParagraphStyles(start,\r
587                                                                   limit,\r
588                                                                   modifier,\r
589                                                                   fDamagedRange);\r
590         if (modified) {\r
591             fTimeStamp += 1;\r
592         }\r
593     }\r
594 \r
595 /**\r
596 * Reset the damaged range to an empty interval, and begin accumulating the damaged\r
597 * range.  The damaged range includes every index where a character, character style,\r
598 * or paragraph style has changed.\r
599 * @see #damagedRangeStart\r
600 * @see #damagedRangeLimit\r
601 */\r
602     public void resetDamagedRange() {\r
603 \r
604         fDamagedRange[0] = Integer.MAX_VALUE;\r
605         fDamagedRange[1] = Integer.MIN_VALUE;\r
606     }\r
607 \r
608 /**\r
609 * Return the start of the damaged range.\r
610 * If the start is\r
611 * <code>Integer.MAX_VALUE</code> and the limit is\r
612 * <code>Integer.MIN_VALUE</code>, then the damaged range\r
613 * is empty.\r
614 * @return the start of the damaged range\r
615 * @see #damagedRangeLimit\r
616 * @see #resetDamagedRange\r
617 */\r
618     public int damagedRangeStart() {\r
619 \r
620         return fDamagedRange[0];\r
621     }\r
622 \r
623 /**\r
624 * Return the limit of the damaged range.\r
625 * If the start is\r
626 * <code>Integer.MAX_VALUE</code> and the limit is\r
627 * <code>Integer.MIN_VALUE</code>, then the damaged range\r
628 * is empty.\r
629 * @return the limit of the damaged range\r
630 * @see #damagedRangeStart\r
631 * @see #resetDamagedRange\r
632 */\r
633     public int damagedRangeLimit() {\r
634 \r
635         return fDamagedRange[1];\r
636     }\r
637 \r
638     public String toString()\r
639     {\r
640         String result ="";\r
641         for (int i = 0; i < length(); i++) {\r
642             result += at(i);\r
643         }\r
644         return result;\r
645     }\r
646 \r
647     //======================================================\r
648     // IMPLEMENTATION\r
649     //======================================================\r
650 \r
651     /* check a range to see if it is well formed and within the bounds of the text */\r
652     private void checkStartLimit(int start, int limit)\r
653     {\r
654         if (start > limit) {\r
655             //System.out.println("Start is less than limit. start:"+start+"; limit:"+limit);\r
656             throw new IllegalArgumentException("Start is greater than limit. start:"+start+"; limit:"+limit);\r
657         }\r
658 \r
659         if (start < 0) {\r
660             //System.out.println("Start is negative. start:"+start);\r
661             throw new IllegalArgumentException("Start is negative. start:"+start);\r
662         }\r
663 \r
664         if (limit > length()) {\r
665             //System.out.println("Limit is greater than length.  limit:"+limit);\r
666             throw new IllegalArgumentException("Limit is greater than length.  limit:"+limit);\r
667         }\r
668     }\r
669 \r
670     private static final boolean LESS_THAN_LENGTH = false;\r
671     private static final boolean NOT_GREATER_THAN_LENGTH = true;\r
672 \r
673     private void checkPos(int pos, boolean endAllowed) {\r
674 \r
675         int lastValidPos = length();\r
676         if (endAllowed == LESS_THAN_LENGTH) {\r
677             --lastValidPos;\r
678         }\r
679 \r
680         if (pos < 0 || pos > lastValidPos) {\r
681             throw new IllegalArgumentException("Position is out of range.");\r
682         }\r
683     }\r
684 }\r