1 /* AttributedStringIterator.java -- Class to iterate over AttributedString
2    Copyright (C) 1998, 1999, 2004, 2005, 2006, 2012 Free Software Foundation, Inc.
3 
4 This file is part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37 
38 
39 package java.text;
40 
41 import java.util.HashMap;
42 import java.util.HashSet;
43 import java.util.Iterator;
44 import java.util.Map;
45 import java.util.Set;
46 
47 import static java.text.AttributedCharacterIterator.Attribute;
48 
49 /**
50   * This class implements the AttributedCharacterIterator interface.  It
51   * is used by AttributedString.getIterator().
52   *
53   * @version 0.0
54   *
55   * @author Aaron M. Renn (arenn@urbanophile.com)
56   */
57 class AttributedStringIterator implements AttributedCharacterIterator
58 {
59 
60   /*************************************************************************/
61 
62   /** The character iterator containing the text */
63   private CharacterIterator ci;
64 
65   /** The list of attributes and ranges */
66   private AttributedString.AttributeRange[] attribs;
67 
68   /**
69    * The list of attributes that the user is interested in.  We may,
70    * at our option, not return any other attributes.
71    */
72   private Attribute[] restricts;
73 
74   /*************************************************************************/
75 
76   /**
77    * Creates a new instance.
78    *
79    * @param sci  an iterator for the string content.
80    * @param attribs  the attribute ranges.
81    * @param beginIndex  the start index.
82    * @param endIndex  the end index.
83    * @param restricts  the attributes that the user is interested in.
84    */
AttributedStringIterator(StringCharacterIterator sci, AttributedString.AttributeRange[] attribs, int beginIndex, int endIndex, AttributedCharacterIterator.Attribute[] restricts)85   AttributedStringIterator(StringCharacterIterator sci,
86                            AttributedString.AttributeRange[] attribs,
87                            int beginIndex, int endIndex,
88                            AttributedCharacterIterator.Attribute[] restricts)
89   {
90     this.ci = new StringCharacterIterator(sci, beginIndex, endIndex);
91     this.attribs = attribs;
92     this.restricts = restricts;
93   }
94 
95   /*************************************************************************/
96 
97   // First we have a bunch of stupid redirects.  If StringCharacterIterator
98   // weren't final, I just would have extended that for this class.  Alas, no.
99 
clone()100   public Object clone()
101   {
102     return(ci.clone());
103   }
104 
current()105   public char current()
106   {
107     return(ci.current());
108   }
109 
next()110   public char next()
111   {
112     return(ci.next());
113   }
114 
previous()115   public char previous()
116   {
117     return(ci.previous());
118   }
119 
first()120   public char first()
121   {
122     return(ci.first());
123   }
124 
last()125   public char last()
126   {
127     return(ci.last());
128   }
129 
getIndex()130   public int getIndex()
131   {
132     return(ci.getIndex());
133   }
134 
setIndex(int index)135   public char setIndex(int index)
136   {
137     return(ci.setIndex(index));
138   }
139 
getBeginIndex()140   public int getBeginIndex()
141   {
142     return(ci.getBeginIndex());
143   }
144 
getEndIndex()145   public int getEndIndex()
146   {
147     return(ci.getEndIndex());
148   }
149 
150   /*
151    * Here is where the AttributedCharacterIterator methods start.
152    */
153 
154   /*************************************************************************/
155 
156   /**
157    * Returns a list of all the attribute keys that are defined anywhere
158    * on this string.
159    */
getAllAttributeKeys()160   public Set<Attribute> getAllAttributeKeys()
161   {
162     HashSet<Attribute> s = new HashSet<Attribute>();
163     if (attribs == null)
164       return(s);
165 
166     for (int i = 0; i < attribs.length; i++)
167     {
168       if (attribs[i].beginIndex > getEndIndex()
169           || attribs[i].endIndex <= getBeginIndex())
170         continue;
171 
172       Iterator<? extends Attribute> iter = attribs[i].attribs.keySet().iterator();
173       while (iter.hasNext())
174         {
175           s.add(iter.next());
176         }
177     }
178 
179     return(s);
180   }
181 
182   /*************************************************************************/
183 
184   /**
185    * Various methods that determine how far the run extends for various
186    * attribute combinations.
187    */
188 
getRunLimit()189   public int getRunLimit()
190   {
191     return getRunLimit(getAllAttributeKeys());
192   }
193 
getRunLimit(Attribute attrib)194   public int getRunLimit(Attribute attrib)
195   {
196     HashSet<Attribute> s = new HashSet<Attribute>();
197     s.add(attrib);
198     return(getRunLimit(s));
199   }
200 
getRunLimit(Set<? extends Attribute> attributeSet)201   public synchronized int getRunLimit(Set<? extends Attribute> attributeSet)
202   {
203     if (attributeSet == null)
204       return ci.getEndIndex();
205 
206     int current = ci.getIndex();
207     int end = ci.getEndIndex();
208     int limit = current;
209     if (current == end)
210       return end;
211     Map<Attribute,Object> runValues = getAttributes();
212     while (limit < end)
213     {
214       Iterator<? extends Attribute> iterator = attributeSet.iterator();
215       while (iterator.hasNext())
216       {
217         Attribute attributeKey = iterator.next();
218         Object v1 = runValues.get(attributeKey);
219         Object v2 = getAttribute(attributeKey, limit + 1);
220         boolean changed = false;
221         // check for equal or both null, if NO return start
222         if (v1 != null)
223           {
224             changed = !v1.equals(v2);
225           }
226         else
227           {
228             changed = (v2 != null);
229           }
230         if (changed)
231           return limit + 1;
232       }
233       // no differences, so increment limit and next and loop again
234       limit++;
235     }
236     return end;
237   }
238 
239   /*************************************************************************/
240 
241   /**
242    * Various methods that determine where the run begins for various
243    * attribute combinations.
244    */
245 
246   /**
247    * Returns the index of the first character in the run containing the current
248    * character and defined by all the attributes defined for that character
249    * position.
250    *
251    * @return The run start index.
252    */
getRunStart()253   public int getRunStart()
254   {
255     return(getRunStart(getAttributes().keySet()));
256   }
257 
258   /**
259    * Returns the index of the first character in the run, defined by the
260    * specified attribute, that contains the current character.
261    *
262    * @param attrib  the attribute (<code>null</code> permitted).
263    *
264    * return The index of the first character in the run.
265    */
getRunStart(Attribute attrib)266   public int getRunStart(Attribute attrib)
267   {
268     if (attrib == null)
269       return ci.getBeginIndex();
270     HashSet<Attribute> s = new HashSet<Attribute>();
271     s.add(attrib);
272     return(getRunStart(s));
273   }
274 
275   /**
276    * Returns the index of the first character in the run, defined by the
277    * specified attribute set, that contains the current character.
278    *
279    * @param attributeSet  the attribute set (<code>null</code> permitted).
280    *
281    * return The index of the first character in the run.
282    */
getRunStart(Set<? extends Attribute> attributeSet)283   public int getRunStart(Set<? extends Attribute> attributeSet)
284   {
285     if (attributeSet == null)
286       return ci.getBeginIndex();
287 
288     int current = ci.getIndex();
289     int begin = ci.getBeginIndex();
290     int start = current;
291     if (start == begin)
292       return begin;
293     Map<Attribute, Object> runValues = getAttributes();
294     int prev = start - 1;
295     while (start > begin)
296     {
297       Iterator<? extends Attribute> iterator = attributeSet.iterator();
298       while (iterator.hasNext())
299       {
300         Attribute attributeKey = iterator.next();
301         Object v1 = runValues.get(attributeKey);
302         Object v2 = getAttribute(attributeKey, prev);
303         boolean changed = false;
304         // check for equal or both null, if NO return start
305         if (v1 != null)
306           {
307             changed = !v1.equals(v2);
308           }
309         else
310           {
311             changed = (v2 != null);
312           }
313         if (changed)
314           return start;
315       }
316       // no differences, so decrement start and prev and loop again
317       start--;
318       prev--;
319     }
320     return start;
321   }
322 
323   /*************************************************************************/
324 
325   /**
326    * Returns the value for an attribute at the specified position.  If the
327    * attribute key (<code>key</code>) is <code>null</code>, the method returns
328    * <code>null</code>.
329    *
330    * @param key  the key (<code>null</code> permitted).
331    * @param pos  the character position.
332    *
333    * @return The attribute value (possibly <code>null</code>).
334    */
getAttribute(AttributedCharacterIterator.Attribute key, int pos)335   private Object getAttribute(AttributedCharacterIterator.Attribute key,
336           int pos)
337   {
338     if (attribs == null)
339       return null;
340     for (int i = attribs.length - 1; i >= 0; i--)
341       {
342         if (pos >= attribs[i].beginIndex && pos < attribs[i].endIndex)
343           {
344             Set<? extends Attribute> keys = attribs[i].attribs.keySet();
345             if (keys.contains(key))
346               {
347                 return attribs[i].attribs.get(key);
348               }
349           }
350       }
351     return null;
352   }
353 
354   /**
355    * Returns the value for an attribute at the current position.  If the
356    * attribute key (<code>key</code>) is <code>null</code>, the method returns
357    * <code>null</code>.
358    *
359    * @param key  the key (<code>null</code> permitted).
360    *
361    * @return The attribute value (possibly <code>null</code>).
362    */
getAttribute(AttributedCharacterIterator.Attribute key)363   public Object getAttribute(AttributedCharacterIterator.Attribute key)
364   {
365     return getAttribute(key, ci.getIndex());
366   }
367 
368   /*************************************************************************/
369 
370   /**
371    * Return a list of all the attributes and values defined for this
372    * character
373    */
getAttributes()374   public Map<Attribute,Object> getAttributes()
375   {
376     HashMap<Attribute,Object> m = new HashMap<Attribute,Object>();
377     if (attribs == null)
378       return(m);
379 
380     for (int i = 0; i < attribs.length; i++)
381       {
382          if ((ci.getIndex() >= attribs[i].beginIndex) &&
383              (ci.getIndex() < attribs[i].endIndex))
384            m.putAll(attribs[i].attribs);
385       }
386 
387     return(m);
388   }
389 
390 } // class AttributedStringIterator
391