| /* AttributedStringIterator.java -- Class to iterate over AttributedString |
| Copyright (C) 1998, 1999, 2004, 2005, 2006, 2012 Free Software Foundation, Inc. |
| |
| This file is part of GNU Classpath. |
| |
| GNU Classpath is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| GNU Classpath is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU Classpath; see the file COPYING. If not, write to the |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
| 02110-1301 USA. |
| |
| Linking this library statically or dynamically with other modules is |
| making a combined work based on this library. Thus, the terms and |
| conditions of the GNU General Public License cover the whole |
| combination. |
| |
| As a special exception, the copyright holders of this library give you |
| permission to link this library with independent modules to produce an |
| executable, regardless of the license terms of these independent |
| modules, and to copy and distribute the resulting executable under |
| terms of your choice, provided that you also meet, for each linked |
| independent module, the terms and conditions of the license of that |
| module. An independent module is a module which is not derived from |
| or based on this library. If you modify this library, you may extend |
| this exception to your version of the library, but you are not |
| obligated to do so. If you do not wish to do so, delete this |
| exception statement from your version. */ |
| |
| |
| package java.text; |
| |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import static java.text.AttributedCharacterIterator.Attribute; |
| |
| /** |
| * This class implements the AttributedCharacterIterator interface. It |
| * is used by AttributedString.getIterator(). |
| * |
| * @version 0.0 |
| * |
| * @author Aaron M. Renn (arenn@urbanophile.com) |
| */ |
| class AttributedStringIterator implements AttributedCharacterIterator |
| { |
| |
| /*************************************************************************/ |
| |
| /** The character iterator containing the text */ |
| private CharacterIterator ci; |
| |
| /** The list of attributes and ranges */ |
| private AttributedString.AttributeRange[] attribs; |
| |
| /** |
| * The list of attributes that the user is interested in. We may, |
| * at our option, not return any other attributes. |
| */ |
| private Attribute[] restricts; |
| |
| /*************************************************************************/ |
| |
| /** |
| * Creates a new instance. |
| * |
| * @param sci an iterator for the string content. |
| * @param attribs the attribute ranges. |
| * @param beginIndex the start index. |
| * @param endIndex the end index. |
| * @param restricts the attributes that the user is interested in. |
| */ |
| AttributedStringIterator(StringCharacterIterator sci, |
| AttributedString.AttributeRange[] attribs, |
| int beginIndex, int endIndex, |
| AttributedCharacterIterator.Attribute[] restricts) |
| { |
| this.ci = new StringCharacterIterator(sci, beginIndex, endIndex); |
| this.attribs = attribs; |
| this.restricts = restricts; |
| } |
| |
| /*************************************************************************/ |
| |
| // First we have a bunch of stupid redirects. If StringCharacterIterator |
| // weren't final, I just would have extended that for this class. Alas, no. |
| |
| public Object clone() |
| { |
| return(ci.clone()); |
| } |
| |
| public char current() |
| { |
| return(ci.current()); |
| } |
| |
| public char next() |
| { |
| return(ci.next()); |
| } |
| |
| public char previous() |
| { |
| return(ci.previous()); |
| } |
| |
| public char first() |
| { |
| return(ci.first()); |
| } |
| |
| public char last() |
| { |
| return(ci.last()); |
| } |
| |
| public int getIndex() |
| { |
| return(ci.getIndex()); |
| } |
| |
| public char setIndex(int index) |
| { |
| return(ci.setIndex(index)); |
| } |
| |
| public int getBeginIndex() |
| { |
| return(ci.getBeginIndex()); |
| } |
| |
| public int getEndIndex() |
| { |
| return(ci.getEndIndex()); |
| } |
| |
| /* |
| * Here is where the AttributedCharacterIterator methods start. |
| */ |
| |
| /*************************************************************************/ |
| |
| /** |
| * Returns a list of all the attribute keys that are defined anywhere |
| * on this string. |
| */ |
| public Set<Attribute> getAllAttributeKeys() |
| { |
| HashSet<Attribute> s = new HashSet<Attribute>(); |
| if (attribs == null) |
| return(s); |
| |
| for (int i = 0; i < attribs.length; i++) |
| { |
| if (attribs[i].beginIndex > getEndIndex() |
| || attribs[i].endIndex <= getBeginIndex()) |
| continue; |
| |
| Iterator<? extends Attribute> iter = attribs[i].attribs.keySet().iterator(); |
| while (iter.hasNext()) |
| { |
| s.add(iter.next()); |
| } |
| } |
| |
| return(s); |
| } |
| |
| /*************************************************************************/ |
| |
| /** |
| * Various methods that determine how far the run extends for various |
| * attribute combinations. |
| */ |
| |
| public int getRunLimit() |
| { |
| return getRunLimit(getAllAttributeKeys()); |
| } |
| |
| public int getRunLimit(Attribute attrib) |
| { |
| HashSet<Attribute> s = new HashSet<Attribute>(); |
| s.add(attrib); |
| return(getRunLimit(s)); |
| } |
| |
| public synchronized int getRunLimit(Set<? extends Attribute> attributeSet) |
| { |
| if (attributeSet == null) |
| return ci.getEndIndex(); |
| |
| int current = ci.getIndex(); |
| int end = ci.getEndIndex(); |
| int limit = current; |
| if (current == end) |
| return end; |
| Map<Attribute,Object> runValues = getAttributes(); |
| while (limit < end) |
| { |
| Iterator<? extends Attribute> iterator = attributeSet.iterator(); |
| while (iterator.hasNext()) |
| { |
| Attribute attributeKey = iterator.next(); |
| Object v1 = runValues.get(attributeKey); |
| Object v2 = getAttribute(attributeKey, limit + 1); |
| boolean changed = false; |
| // check for equal or both null, if NO return start |
| if (v1 != null) |
| { |
| changed = !v1.equals(v2); |
| } |
| else |
| { |
| changed = (v2 != null); |
| } |
| if (changed) |
| return limit + 1; |
| } |
| // no differences, so increment limit and next and loop again |
| limit++; |
| } |
| return end; |
| } |
| |
| /*************************************************************************/ |
| |
| /** |
| * Various methods that determine where the run begins for various |
| * attribute combinations. |
| */ |
| |
| /** |
| * Returns the index of the first character in the run containing the current |
| * character and defined by all the attributes defined for that character |
| * position. |
| * |
| * @return The run start index. |
| */ |
| public int getRunStart() |
| { |
| return(getRunStart(getAttributes().keySet())); |
| } |
| |
| /** |
| * Returns the index of the first character in the run, defined by the |
| * specified attribute, that contains the current character. |
| * |
| * @param attrib the attribute (<code>null</code> permitted). |
| * |
| * return The index of the first character in the run. |
| */ |
| public int getRunStart(Attribute attrib) |
| { |
| if (attrib == null) |
| return ci.getBeginIndex(); |
| HashSet<Attribute> s = new HashSet<Attribute>(); |
| s.add(attrib); |
| return(getRunStart(s)); |
| } |
| |
| /** |
| * Returns the index of the first character in the run, defined by the |
| * specified attribute set, that contains the current character. |
| * |
| * @param attributeSet the attribute set (<code>null</code> permitted). |
| * |
| * return The index of the first character in the run. |
| */ |
| public int getRunStart(Set<? extends Attribute> attributeSet) |
| { |
| if (attributeSet == null) |
| return ci.getBeginIndex(); |
| |
| int current = ci.getIndex(); |
| int begin = ci.getBeginIndex(); |
| int start = current; |
| if (start == begin) |
| return begin; |
| Map<Attribute, Object> runValues = getAttributes(); |
| int prev = start - 1; |
| while (start > begin) |
| { |
| Iterator<? extends Attribute> iterator = attributeSet.iterator(); |
| while (iterator.hasNext()) |
| { |
| Attribute attributeKey = iterator.next(); |
| Object v1 = runValues.get(attributeKey); |
| Object v2 = getAttribute(attributeKey, prev); |
| boolean changed = false; |
| // check for equal or both null, if NO return start |
| if (v1 != null) |
| { |
| changed = !v1.equals(v2); |
| } |
| else |
| { |
| changed = (v2 != null); |
| } |
| if (changed) |
| return start; |
| } |
| // no differences, so decrement start and prev and loop again |
| start--; |
| prev--; |
| } |
| return start; |
| } |
| |
| /*************************************************************************/ |
| |
| /** |
| * Returns the value for an attribute at the specified position. If the |
| * attribute key (<code>key</code>) is <code>null</code>, the method returns |
| * <code>null</code>. |
| * |
| * @param key the key (<code>null</code> permitted). |
| * @param pos the character position. |
| * |
| * @return The attribute value (possibly <code>null</code>). |
| */ |
| private Object getAttribute(AttributedCharacterIterator.Attribute key, |
| int pos) |
| { |
| if (attribs == null) |
| return null; |
| for (int i = attribs.length - 1; i >= 0; i--) |
| { |
| if (pos >= attribs[i].beginIndex && pos < attribs[i].endIndex) |
| { |
| Set<? extends Attribute> keys = attribs[i].attribs.keySet(); |
| if (keys.contains(key)) |
| { |
| return attribs[i].attribs.get(key); |
| } |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Returns the value for an attribute at the current position. If the |
| * attribute key (<code>key</code>) is <code>null</code>, the method returns |
| * <code>null</code>. |
| * |
| * @param key the key (<code>null</code> permitted). |
| * |
| * @return The attribute value (possibly <code>null</code>). |
| */ |
| public Object getAttribute(AttributedCharacterIterator.Attribute key) |
| { |
| return getAttribute(key, ci.getIndex()); |
| } |
| |
| /*************************************************************************/ |
| |
| /** |
| * Return a list of all the attributes and values defined for this |
| * character |
| */ |
| public Map<Attribute,Object> getAttributes() |
| { |
| HashMap<Attribute,Object> m = new HashMap<Attribute,Object>(); |
| if (attribs == null) |
| return(m); |
| |
| for (int i = 0; i < attribs.length; i++) |
| { |
| if ((ci.getIndex() >= attribs[i].beginIndex) && |
| (ci.getIndex() < attribs[i].endIndex)) |
| m.putAll(attribs[i].attribs); |
| } |
| |
| return(m); |
| } |
| |
| } // class AttributedStringIterator |