001: /*
002: * (C) Copyright IBM Corp. 1998-2004. All Rights Reserved.
003: *
004: * The program is provided "as is" without any warranty express or
005: * implied, including the warranty of non-infringement and the implied
006: * warranties of merchantibility and fitness for a particular purpose.
007: * IBM will not be liable for any damages suffered by you as a result
008: * of using the Program. In no event will IBM be liable for any
009: * special, indirect or consequential damages or lost profits even if
010: * IBM has been advised of the possibility of their occurrence. IBM
011: * will not be liable for any third party claims against you.
012: */
013: package com.ibm.richtext.styledtext;
014:
015: import com.ibm.richtext.textlayout.attributes.AttributeMap;
016: import java.text.CharacterIterator;
017: import java.awt.datatransfer.DataFlavor;
018:
019: /**
020: * MConstText is a base class for text with multiple character and
021: * paragraph styles. The text is a sequence of Unicode characters,
022: * represented by <code>char</code>. Character and paragraph
023: * styles are represented by the <code>AttributeMap</code> class.
024: * <p>
025: * Characters in the text are accessed with an integer index using the
026: * <code>at</code> method.
027: * Valid indices are between 0 and (length-1), where length is the number
028: * of characters in the text. Additionally, the
029: * characters in the text may be accessed through a
030: * <code>java.text.CharacterIterator</code>.
031: * <p>
032: * Every character in the text has a character style associated with it,
033: * represented by the <code>AttributeMap</code> class. The character
034: * style for a particular character can be obtained using the
035: * <code>characterStyleAt</code> method.
036: * <p>
037: * Each character in the text is contained in a paragraph. A paragraph
038: * is a range of text including and terminated by a
039: * paragraph separator (either <code>\n</code> or <code>U+2029</code>).
040: * Every
041: * paragraph has a paragraph style associated with it, represented
042: * by the <code>AttributeMap</code> class. Paragraph boundaries and
043: * styles can be obtained from the MConstText.
044: * <p>
045: * This class does not have methods for modifying the text or styles.
046: * However, subclasses may add this capability, so it is not safe to
047: * assume that an MConstText instance is immutable. In particular,
048: * the MText class adds modification protocol to this class. Clients
049: * can detect whether an MConstText has changed by keeping track of its
050: * timestamp.
051: * <p>
052: * A DataFlavor for clipboard content is defined in this class. Using
053: * this DataFlavor insures that all clients will recognize MConstText
054: * content on the clipboard.
055: * @see MText
056: * @see AttributeMap
057: * @see java.text.CharacterIterator
058: * @see java.awt.datatransfer.DataFlavor
059: */
060: public abstract class MConstText {
061:
062: static final String COPYRIGHT = "(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
063: /**
064: * The DataFlavor for MConstText clipboard content. Used to
065: * indicate that clipboard data has an MConstText representation.
066: */
067: public static final DataFlavor styledTextFlavor = new DataFlavor(
068: MConstText.class, "Styled Text");
069:
070: protected MConstText() {
071: }
072:
073: //========================================================
074: // CHARACTER ACCESS
075: //========================================================
076: /**
077: * Return the character at offset <code>pos</code>.
078: * @param pos a valid offset into the text
079: * @return the character at offset <code>pos</code>
080: */
081: public abstract char at(int pos);
082:
083: /**
084: * Copy the characters in the range [<code>start</code>, <code>limit</code>)
085: * into the array <code>dst</code>, beginning at <code>dstStart</code>.
086: * @param start offset of first character which will be copied into the array
087: * @param limit offset immediately after the last character which will be copied into the array
088: * @param dst array in which to copy characters. The length of <code>dst</code> must be at least
089: * (<code>dstStart + limit - start</code>).
090: */
091: public abstract void extractChars(int start, int limit, char[] dst,
092: int dstStart);
093:
094: /**
095: * Create an MConstText containing the characters and styles in the range
096: * [<code>start</code>, <code>limit</code>).
097: * @param start offset of first character in the new text
098: * @param limit offset immediately after the last character in the new text
099: * @return an MConstText object containing the characters and styles in the given range
100: */
101: public abstract MConstText extract(int start, int limit);
102:
103: /**
104: * Create a <code>java.text.CharacterIterator</code> over all
105: * of the characters in the text. Default implementation calls
106: * <code>createCharacterIterator(0, length())</code>
107: * @return a <code>java.text.CharacterIterator</code> over all
108: * of the characters in the text
109: */
110: public CharacterIterator createCharacterIterator() {
111:
112: return createCharacterIterator(0, length());
113: }
114:
115: /**
116: * Create a <code>java.text.CharacterIterator</code> over the
117: * given range of characters in the text.
118: * @param start the first index in the iteration range
119: * @param limit the index after the last character in the iteration range
120: * @return a <code>java.text.CharacterIterator</code> over the
121: * given range
122: */
123: public abstract CharacterIterator createCharacterIterator(
124: int start, int limit);
125:
126: //========================================================
127: // SIZE/CAPACITY
128: //========================================================
129: /**
130: * Return the length of the MConstText object. The length is the number of characters in the text.
131: * @return the length of the MConstText object
132: */
133: public abstract int length();
134:
135: //========================================================
136: // Character styles
137: //========================================================
138:
139: /**
140: * Return the index of the first character in the character style run
141: * containing pos. All characters in a style run have the same character
142: * style.
143: * @return the style at offset <code>pos</code>
144: */
145: public abstract int characterStyleStart(int pos);
146:
147: /**
148: * Return the index after the last character in the character style run
149: * containing pos. All characters in a style run have the same character
150: * style.
151: * @return the style at offset <code>pos</code>
152: */
153: public abstract int characterStyleLimit(int pos);
154:
155: /**
156: * Return the style applied to the character at offset <code>pos</code>.
157: * @param pos a valid offset into the text
158: * @return the style at offset <code>pos</code>
159: */
160: public abstract AttributeMap characterStyleAt(int pos);
161:
162: //========================================================
163: // PARAGRAPH BOUNDARIES
164: //========================================================
165: /**
166: * Return the start of the paragraph containing the character at offset <code>pos</code>.
167: * @param pos a valid offset into the text
168: * @return the start of the paragraph containing the character at offset <code>pos</code>
169: */
170: public abstract int paragraphStart(int pos);
171:
172: /**
173: * Return the limit of the paragraph containing the character at offset <code>pos</code>.
174: * @param pos a valid offset into the text
175: * @return the limit of the paragraph containing the character at offset <code>pos</code>
176: */
177: public abstract int paragraphLimit(int pos);
178:
179: /**
180: * Return the paragraph style applied to the paragraph containing offset <code>pos</code>.
181: * @param pos a valid offset into the text
182: * @return the paragraph style in effect at <code>pos</code>
183: */
184: public abstract AttributeMap paragraphStyleAt(int pos);
185:
186: /**
187: * Return the current time stamp. The time stamp is
188: * incremented whenever the contents of the MConstText changes.
189: * @return the current paragraph style time stamp
190: */
191: public abstract int getTimeStamp();
192:
193: /**
194: * Return the start of the damaged range. If the start is not less
195: * than the the limit of the damaged range, then the damaged range
196: * is empty.
197: * @return the start of the damaged range
198: * @see #damagedRangeLimit
199: * @see MText#resetDamagedRange
200: */
201: public abstract int damagedRangeStart();
202:
203: /**
204: * Return the limit of the damaged range. If the start is not less
205: * than the the limit of the damaged range, then the damaged range
206: * is empty.
207: * @return the start of the damaged range
208: * @see #damagedRangeStart
209: * @see MText#resetDamagedRange
210: */
211: public abstract int damagedRangeLimit();
212:
213: //========================================================
214: // Equality and hashCode
215: //========================================================
216: /**
217: * Compare this to another Object for equality. This is
218: * equal to rhs if rhs is an MConstText which is equal
219: * to this.
220: * @param rhs Object to compare to
221: * @return true if this equals <code>rhs</code>
222: */
223: public final boolean equals(Object rhs) {
224:
225: MConstText otherText;
226:
227: try {
228: otherText = (MConstText) rhs;
229: } catch (ClassCastException e) {
230: return false;
231: }
232:
233: return equals(otherText);
234: }
235:
236: /**
237: * Compare this to another MConstText for equality. This is
238: * equal to rhs if the characters and styles in rhs are the
239: * same as this. Subclasses may override this implementation
240: * for efficiency, but they should preserve these semantics.
241: * Determining that two MConstText instances are equal may be
242: * an expensive operation, since every character and style must
243: * be compared.
244: * @param rhs Object to compare to
245: * @return true if this equals <code>rhs</code>
246: */
247: public boolean equals(MConstText rhs) {
248:
249: if (rhs == null) {
250: return false;
251: }
252:
253: if (rhs == this ) {
254: return true;
255: }
256:
257: if (hashCode() != rhs.hashCode()) {
258: return false;
259: }
260:
261: int length = length();
262: if (length != rhs.length()) {
263: return false;
264: }
265:
266: for (int i = 0; i < length; i++) {
267: if (i < length && at(i) != rhs.at(i)) {
268: return false;
269: }
270: }
271:
272: for (int start = 0; start < length;) {
273: if (!characterStyleAt(start).equals(
274: rhs.characterStyleAt(start))) {
275: return false;
276: }
277: int limit = characterStyleLimit(start);
278: if (limit != rhs.characterStyleLimit(start)) {
279: return false;
280: }
281: start = limit;
282: }
283:
284: for (int start = 0; start < length;) {
285:
286: if (!paragraphStyleAt(start).equals(
287: rhs.paragraphStyleAt(start))) {
288: return false;
289: }
290: start = paragraphLimit(start);
291: }
292:
293: return paragraphStyleAt(length).equals(
294: rhs.paragraphStyleAt(length));
295: }
296:
297: /**
298: * Return the hashCode for this MConstText. An empty MConstText
299: * has hashCode 0; a nonempty MConstText's hashCode is
300: * <blockquote><pre>
301: * at(0) +
302: * at(length/2)*31^1 +
303: * at(length-1)*31^2 +
304: * characterStyleAt(0).hashCode()*31^3 +
305: * paragraphStyleAt(length-1).hashCode()*31^4
306: * </pre></blockquote>
307: * where <code>^</code> is exponentiation (not bitwise XOR).
308: */
309: public final int hashCode() {
310:
311: int hashCode = 0;
312: int length = length();
313:
314: if (length > 0) {
315: hashCode = paragraphStyleAt(length - 1).hashCode();
316: hashCode = hashCode * 31 + characterStyleAt(0).hashCode();
317: hashCode = hashCode * 31 + at(length - 1);
318: hashCode = hashCode * 31 + at(length / 2);
319: hashCode = hashCode * 31 + at(0);
320: }
321:
322: return hashCode;
323: }
324: }
|