]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-4_2_1-src/src/com/ibm/richtext/textformat/MTextIterator.java
icu4jsrc
[Dictionary.git] / jars / icu4j-4_2_1-src / src / com / ibm / richtext / textformat / MTextIterator.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 // Requires Java2\r
14 package com.ibm.richtext.textformat;\r
15 \r
16 import com.ibm.richtext.styledtext.MConstText;\r
17 import java.text.CharacterIterator;\r
18 \r
19 import com.ibm.richtext.textlayout.attributes.AttributeMap;\r
20 \r
21 ///*JDK12IMPORTS\r
22 import java.text.AttributedCharacterIterator;\r
23 import java.util.Map;\r
24 import java.util.Set;\r
25 //JDK12IMPORTS*/\r
26 \r
27 /*JDK11IMPORTS\r
28 import com.ibm.richtext.textlayout.attributes.AttributedCharacterIterator;\r
29 import com.ibm.richtext.textlayout.attributes.AttributedCharacterIterator.Attribute;\r
30 import com.ibm.richtext.textlayout.attributes.Map;\r
31 JDK11IMPORTS*/\r
32 \r
33 /**\r
34  * An AttributedCharacterIterator over an MConstText.\r
35  */\r
36 public final class MTextIterator implements AttributedCharacterIterator,\r
37                                             Cloneable {\r
38 \r
39     static final String COPYRIGHT =\r
40                 "(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";\r
41     // memory leak, since this cache is never flushed\r
42 \r
43     private static class Matcher {\r
44         \r
45         boolean matches(Map lhs, Map rhs, Object query) {\r
46             \r
47             Object lhsVal = lhs.get(query);\r
48             Object rhsVal = rhs.get(query);\r
49             \r
50             if (lhsVal == null) {\r
51                 return rhsVal == null;\r
52             }\r
53             else {\r
54                 return lhsVal.equals(rhsVal);\r
55             }\r
56         }\r
57     }\r
58     \r
59     private static final Matcher ATTR_MATCHER = new Matcher();\r
60     \r
61     // Not quite optimal.  Could have a matcher that would decompose\r
62     // a set once for repeated queries.  Of course that would require\r
63     // allocation...\r
64 ///*JDK12IMPORTS\r
65     private static final Matcher SET_MATCHER = new Matcher() {\r
66         \r
67         boolean matches(Map lhs, Map rhs, Object query) {\r
68             \r
69             // Not using Iterator to simplify 1.1 port.\r
70             Object[] elements = ((Set)query).toArray();\r
71             for (int i=0; i < elements.length; i++) {\r
72                 if (!super.matches(lhs, rhs, elements[i])) {\r
73                     return false;\r
74                 }\r
75             }\r
76             return true;\r
77         }\r
78     };\r
79 //JDK12IMPORTS*/\r
80     \r
81     private final class StyleCache {\r
82 \r
83         private int fRunStart = 0;\r
84         private int fRunLimit = -1;\r
85         private int fRangeStart;\r
86         private int fRangeLimit;\r
87         private AttributeMap fStyle;\r
88 \r
89         StyleCache(MConstText text, int start, int limit) {\r
90             fText = text;\r
91             fRangeStart = start;\r
92             fRangeLimit = limit;\r
93             update(start);\r
94         }\r
95 \r
96         private void update(int pos) {\r
97             if (pos < fRunStart || pos >= fRunLimit) {\r
98                 AttributeMap style = AttributeMap.EMPTY_ATTRIBUTE_MAP;\r
99                 if (pos < fRangeStart) {\r
100                     fRunLimit = fRangeStart;\r
101                     fRunStart = Integer.MIN_VALUE;\r
102                 }\r
103                 else if (pos > fRangeLimit) {\r
104                     fRunStart = fRangeLimit;\r
105                     fRunLimit = Integer.MAX_VALUE;\r
106                 }\r
107                 else {\r
108                     fRunStart = Math.max(fRangeStart, fText.characterStyleStart(pos));\r
109                     fRunStart = Math.max(fRunStart, fText.paragraphStart(pos));\r
110                     \r
111                     fRunLimit = Math.min(fRangeLimit, fText.characterStyleLimit(pos));\r
112                     fRunLimit = Math.min(fRunLimit, fText.paragraphLimit(pos));\r
113                     if (fRunStart < fRunLimit) {\r
114                         style = fText.paragraphStyleAt(pos);\r
115                         style = style.addAttributes(fText.characterStyleAt(pos));\r
116                     }\r
117                 }\r
118                 fStyle = fFontResolver.applyFont(style);\r
119             }\r
120         }\r
121 \r
122         int getRunStart(int pos) {\r
123             update(pos);\r
124             return fRunStart;\r
125         }\r
126 \r
127         int getRunLimit(int pos) {\r
128             update(pos);\r
129             return fRunLimit;\r
130         }\r
131 \r
132         Map getStyle(int pos) {\r
133             update(pos);\r
134             return fStyle;\r
135         }\r
136     }\r
137 \r
138     private MConstText fText;\r
139     private CharacterIterator fCharIter;\r
140     private FontResolver fFontResolver;\r
141     \r
142     private StyleCache fStyleCache;\r
143 \r
144     /**\r
145      * Create an MTextIterator over the range [start, limit).\r
146      */\r
147     public MTextIterator(MConstText text, \r
148                          FontResolver resolver,\r
149                          int start, \r
150                          int limit) {\r
151 \r
152         fText = text;\r
153         fFontResolver = resolver;\r
154         fCharIter = text.createCharacterIterator(start, limit);\r
155 \r
156         fStyleCache = new StyleCache(text, start, limit);\r
157     }\r
158 \r
159     /**\r
160      * Sets the position to getBeginIndex() and returns the character at that\r
161      * position.\r
162      * @return the first character in the text, or DONE if the text is empty\r
163      * @see #getBeginIndex\r
164      */\r
165     public char first() {\r
166         return fCharIter.first();\r
167     }\r
168 \r
169     /**\r
170      * Sets the position to getEndIndex()-1 (getEndIndex() if the text is empty)\r
171      * and returns the character at that position.\r
172      * @return the last character in the text, or DONE if the text is empty\r
173      * @see #getEndIndex\r
174      */\r
175     public char last() {\r
176         return fCharIter.last();\r
177     }\r
178 \r
179     /**\r
180      * Gets the character at the current position (as returned by getIndex()).\r
181      * @return the character at the current position or DONE if the current\r
182      * position is off the end of the text.\r
183      * @see #getIndex\r
184      */\r
185     public char current() {\r
186         return fCharIter.current();\r
187     }\r
188 \r
189     /**\r
190      * Increments the iterator's index by one and returns the character\r
191      * at the new index.  If the resulting index is greater or equal\r
192      * to getEndIndex(), the current index is reset to getEndIndex() and\r
193      * a value of DONE is returned.\r
194      * @return the character at the new position or DONE if the new\r
195      * position is off the end of the text range.\r
196      */\r
197     public char next() {\r
198         return fCharIter.next();\r
199     }\r
200 \r
201     /**\r
202      * Decrements the iterator's index by one and returns the character\r
203      * at the new index. If the current index is getBeginIndex(), the index\r
204      * remains at getBeginIndex() and a value of DONE is returned.\r
205      * @return the character at the new position or DONE if the current\r
206      * position is equal to getBeginIndex().\r
207      */\r
208     public char previous() {\r
209         return fCharIter.previous();\r
210     }\r
211 \r
212     /**\r
213      * Sets the position to the specified position in the text and returns that\r
214      * character.\r
215      * @param position the position within the text.  Valid values range from\r
216      * getBeginIndex() to getEndIndex().  An IllegalArgumentException is thrown\r
217      * if an invalid value is supplied.\r
218      * @return the character at the specified position or DONE if the specified position is equal to getEndIndex()\r
219      */\r
220     public char setIndex(int position) {\r
221         return fCharIter.setIndex(position);\r
222     }\r
223 \r
224     /**\r
225      * Returns the start index of the text.\r
226      * @return the index at which the text begins.\r
227      */\r
228     public int getBeginIndex() {\r
229         return fCharIter.getBeginIndex();\r
230     }\r
231 \r
232     /**\r
233      * Returns the end index of the text.  This index is the index of the first\r
234      * character following the end of the text.\r
235      * @return the index after the last character in the text\r
236      */\r
237     public int getEndIndex() {\r
238         return fCharIter.getEndIndex();\r
239     }\r
240 \r
241     /**\r
242      * Returns the current index.\r
243      * @return the current index.\r
244      */\r
245     public int getIndex() {\r
246         return fCharIter.getIndex();\r
247     }\r
248 \r
249     /**\r
250      * Returns the index of the first character of the run\r
251      * with respect to all attributes containing the current character.\r
252      */\r
253     public int getRunStart() {\r
254         return fStyleCache.getRunStart(fCharIter.getIndex());\r
255     }\r
256 \r
257     /**\r
258      * Returns the index of the first character of the run\r
259      * with respect to the given attribute containing the current character.\r
260      */\r
261     public int getRunStart(Object attribute) {\r
262 \r
263         return getRunStart(attribute, ATTR_MATCHER);\r
264     }\r
265 \r
266     /**\r
267      * Returns the index of the first character of the run\r
268      * with respect to the given attribute containing the current character.\r
269      */\r
270 ///*JDK12IMPORTS\r
271     public int getRunStart(Attribute attribute) {\r
272 \r
273         return getRunStart(attribute, ATTR_MATCHER);\r
274     }\r
275 //JDK12IMPORTS*/\r
276 \r
277     /**\r
278      * Returns the index of the first character of the run\r
279      * with respect to the given attributes containing the current character.\r
280      */\r
281 ///*JDK12IMPORTS\r
282     public int getRunStart(Set attributes) {\r
283 \r
284         return getRunStart(attributes, SET_MATCHER);\r
285     }\r
286 //JDK12IMPORTS*/\r
287     \r
288     private int getRunStart(Object query, Matcher matcher) {\r
289 \r
290         int runStart = getRunStart();\r
291         int rangeStart = getBeginIndex();\r
292         Map initialStyle = getAttributes();\r
293         \r
294         while (runStart > rangeStart) {\r
295             AttributeMap style = fText.characterStyleAt(runStart-1);\r
296             if (!matcher.matches(initialStyle, style, query)) {\r
297                 return runStart;\r
298             }\r
299             runStart = fText.characterStyleStart(runStart-1);\r
300         }\r
301         return rangeStart;\r
302     }\r
303     \r
304     /**\r
305      * Returns the index of the first character following the run\r
306      * with respect to all attributes containing the current character.\r
307      */\r
308     public int getRunLimit() {\r
309         return fStyleCache.getRunLimit(fCharIter.getIndex());\r
310     }\r
311 \r
312     /**\r
313      * Returns the index of the first character following the run\r
314      * with respect to the given attribute containing the current character.\r
315      */\r
316     public int getRunLimit(Object attribute) {\r
317         \r
318         return getRunLimit(attribute, ATTR_MATCHER);\r
319     }\r
320 \r
321     /**\r
322      * Returns the index of the first character following the run\r
323      * with respect to the given attribute containing the current character.\r
324      */\r
325 ///*JDK12IMPORTS\r
326     public int getRunLimit(Attribute attribute) {\r
327         \r
328         return getRunLimit(attribute, ATTR_MATCHER);\r
329     }\r
330 //JDK12IMPORTS*/\r
331 \r
332     /**\r
333      * Returns the index of the first character following the run\r
334      * with respect to the given attributes containing the current character.\r
335      */\r
336 ///*JDK12IMPORTS\r
337     public int getRunLimit(Set attributes) {\r
338         \r
339         return getRunLimit(attributes, SET_MATCHER);\r
340     }\r
341 //JDK12IMPORTS*/\r
342 \r
343     private int getRunLimit(Object query, Matcher matcher) {\r
344 \r
345         int runLimit = getRunLimit();\r
346         int rangeLimit = getEndIndex();\r
347         Map initialStyle = getAttributes();\r
348         \r
349         while (runLimit < rangeLimit) {\r
350             AttributeMap style = fText.characterStyleAt(runLimit);\r
351             if (!matcher.matches(initialStyle, style, query)) {\r
352                 return runLimit;\r
353             }\r
354             runLimit = fText.characterStyleLimit(runLimit);\r
355         }\r
356         return rangeLimit;\r
357     }\r
358     \r
359     /**\r
360      * Returns a map with the attributes defined on the current\r
361      * character.\r
362      */\r
363     public Map getAttributes() {\r
364         return fStyleCache.getStyle(fCharIter.getIndex());\r
365     }\r
366 \r
367     /**\r
368      * Returns the value of the named attribute for the current character.\r
369      * Returns null if the attribute is not defined.\r
370      * @param attribute the key of the attribute whose value is requested.\r
371      */\r
372     public Object getAttribute(Object attribute) {\r
373         return getAttributes().get(attribute);\r
374     }\r
375 \r
376     /**\r
377      * Returns the value of the named attribute for the current character.\r
378      * Returns null if the attribute is not defined.\r
379      * @param attribute the key of the attribute whose value is requested.\r
380      */\r
381     public Object getAttribute(Attribute attribute) {\r
382         return getAttributes().get(attribute);\r
383     }\r
384 \r
385     /**\r
386      * Returns the keys of all attributes defined on the\r
387      * iterator's text range. The set is empty if no\r
388      * attributes are defined.\r
389      */\r
390 ///*JDK12IMPORTS\r
391     public Set getAllAttributeKeys() {\r
392         throw new Error("Implement this method!");\r
393     }\r
394 //JDK12IMPORTS*/\r
395 \r
396     public Object clone() {\r
397         return new MTextIterator(fText,\r
398                                  fFontResolver,\r
399                                  getBeginIndex(),\r
400                                  getEndIndex());\r
401     }\r
402 }\r