1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/*
2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Licensed to the Apache Software Foundation (ASF) under one or more
3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * contributor license agreements.  See the NOTICE file distributed with
4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * this work for additional information regarding copyright ownership.
5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * The ASF licenses this file to You under the Apache License, Version 2.0
6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * (the "License"); you may not use this file except in compliance with
7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the License.  You may obtain a copy of the License at
8f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes *
9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0
10f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes *
11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software
12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * License for the specific language governing permissions and limitations under
15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the License.
16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpackage java.text;
19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
20adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.text.AttributedCharacterIterator.Attribute;
21adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.ArrayList;
22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Arrays;
23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.HashMap;
24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.HashSet;
25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Iterator;
26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.List;
27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.ListIterator;
28adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Map;
29adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Set;
30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
31adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Holds a string with attributes describing the characters of
33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * this string.
34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
35adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic class AttributedString {
36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    String text;
38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
39adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    Map<AttributedCharacterIterator.Attribute, List<Range>> attributeMap;
40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    static class Range {
42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int start;
43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
44adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int end;
45adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Object value;
47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Range(int s, int e, Object v) {
49adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            start = s;
50adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            end = e;
51adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            value = v;
52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
53adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
54adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    static class AttributedIterator implements AttributedCharacterIterator {
56adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
57adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        private int begin, end, offset;
58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
59adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        private AttributedString attrString;
60adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
61adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        private HashSet<Attribute> attributesAllowed;
62adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
63adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        AttributedIterator(AttributedString attrString) {
64adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            this.attrString = attrString;
65adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            begin = 0;
66adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            end = attrString.text.length();
67adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            offset = 0;
68adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
69adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
70adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        AttributedIterator(AttributedString attrString,
71adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                AttributedCharacterIterator.Attribute[] attributes, int begin,
72adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                int end) {
73adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (begin < 0 || end > attrString.text.length() || begin > end) {
74adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                throw new IllegalArgumentException();
75adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
76adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            this.begin = begin;
77adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            this.end = end;
78adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            offset = begin;
79adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            this.attrString = attrString;
80adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (attributes != null) {
81adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                HashSet<Attribute> set = new HashSet<Attribute>(
82adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        (attributes.length * 4 / 3) + 1);
83adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                for (int i = attributes.length; --i >= 0;) {
84adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    set.add(attributes[i]);
85adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
86adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                attributesAllowed = set;
87adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
88adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
89adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
90adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /**
91adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * Returns a new {@code AttributedIterator} with the same source string,
92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * begin, end, and current index as this attributed iterator.
93f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes         *
94adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * @return a shallow copy of this attributed iterator.
95adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * @see java.lang.Cloneable
96adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
97adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        @Override
98adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        @SuppressWarnings("unchecked")
99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public Object clone() {
100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            try {
101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                AttributedIterator clone = (AttributedIterator) super.clone();
102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (attributesAllowed != null) {
103adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    clone.attributesAllowed = (HashSet<Attribute>) attributesAllowed
104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            .clone();
105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return clone;
107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } catch (CloneNotSupportedException e) {
108fb0ec0e650bf8be35acb0d47da0311a7c446aa33Elliott Hughes                throw new AssertionError(e);
109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
112adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public char current() {
113adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (offset == end) {
114adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return DONE;
115adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return attrString.text.charAt(offset);
117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
119adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public char first() {
120adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (begin == end) {
121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return DONE;
122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            offset = begin;
124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return attrString.text.charAt(offset);
125adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /**
128adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * Returns the begin index in the source string.
129f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes         *
130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * @return the index of the first character to iterate.
131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public int getBeginIndex() {
133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return begin;
134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /**
137adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * Returns the end index in the source String.
138f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes         *
139adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * @return the index one past the last character to iterate.
140adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
141adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public int getEndIndex() {
142adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return end;
143adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /**
146adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * Returns the current index in the source String.
147f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes         *
148adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * @return the current index.
149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
150adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public int getIndex() {
151adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return offset;
152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
153adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
154adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        private boolean inRange(Range range) {
155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (!(range.value instanceof Annotation)) {
156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return true;
157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return range.start >= begin && range.start < end
159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    && range.end > begin && range.end <= end;
160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
161adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        private boolean inRange(List<Range> ranges) {
163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            Iterator<Range> it = ranges.iterator();
164adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            while (it.hasNext()) {
165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                Range range = it.next();
166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (range.start >= begin && range.start < end) {
167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    return !(range.value instanceof Annotation)
168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            || (range.end > begin && range.end <= end);
169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                } else if (range.end > begin && range.end <= end) {
170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    return !(range.value instanceof Annotation)
171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            || (range.start >= begin && range.start < end);
172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return false;
175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /**
178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * Returns a set of attributes present in the {@code AttributedString}.
1799b354e75f2418e54638e02d153216660b67d01b8Jesse Wilson         * An empty set returned indicates that no attributes where defined.
1809b354e75f2418e54638e02d153216660b67d01b8Jesse Wilson         *
181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * @return a set of attribute keys that may be empty.
182adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public Set<AttributedIterator.Attribute> getAllAttributeKeys() {
184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (begin == 0 && end == attrString.text.length()
185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    && attributesAllowed == null) {
186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return attrString.attributeMap.keySet();
187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            Set<AttributedIterator.Attribute> result = new HashSet<Attribute>(
190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    (attrString.attributeMap.size() * 4 / 3) + 1);
191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            Iterator<Map.Entry<Attribute, List<Range>>> it = attrString.attributeMap
192adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    .entrySet().iterator();
193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            while (it.hasNext()) {
194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                Map.Entry<Attribute, List<Range>> entry = it.next();
195adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (attributesAllowed == null
196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        || attributesAllowed.contains(entry.getKey())) {
197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    List<Range> ranges = entry.getValue();
198adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    if (inRange(ranges)) {
199adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        result.add(entry.getKey());
200adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
201adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
202adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
203adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return result;
204adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
205adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
206adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        private Object currentValue(List<Range> ranges) {
207adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            Iterator<Range> it = ranges.iterator();
208adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            while (it.hasNext()) {
209adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                Range range = it.next();
210adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (offset >= range.start && offset < range.end) {
211adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    return inRange(range) ? range.value : null;
212adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
213adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
214adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return null;
215adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
216adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
217adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public Object getAttribute(
218adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                AttributedCharacterIterator.Attribute attribute) {
219adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (attributesAllowed != null
220adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    && !attributesAllowed.contains(attribute)) {
221adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return null;
222adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
223adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            ArrayList<Range> ranges = (ArrayList<Range>) attrString.attributeMap
224adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    .get(attribute);
225adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (ranges == null) {
226adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return null;
227adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
228adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return currentValue(ranges);
229adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
230adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
231adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public Map<Attribute, Object> getAttributes() {
232adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            Map<Attribute, Object> result = new HashMap<Attribute, Object>(
233adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    (attrString.attributeMap.size() * 4 / 3) + 1);
234adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            Iterator<Map.Entry<Attribute, List<Range>>> it = attrString.attributeMap
235adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    .entrySet().iterator();
236adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            while (it.hasNext()) {
237adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                Map.Entry<Attribute, List<Range>> entry = it.next();
238adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (attributesAllowed == null
239adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        || attributesAllowed.contains(entry.getKey())) {
240adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    Object value = currentValue(entry.getValue());
241adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    if (value != null) {
242adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        result.put(entry.getKey(), value);
243adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
244adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
245adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
246adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return result;
247adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
248adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
249adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public int getRunLimit() {
250adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return getRunLimit(getAllAttributeKeys());
251adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
252adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
253adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        private int runLimit(List<Range> ranges) {
254adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int result = end;
255adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            ListIterator<Range> it = ranges.listIterator(ranges.size());
256adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            while (it.hasPrevious()) {
257adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                Range range = it.previous();
258adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (range.end <= begin) {
259adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    break;
260adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
261adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (offset >= range.start && offset < range.end) {
262adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    return inRange(range) ? range.end : result;
263adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                } else if (offset >= range.end) {
264adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    break;
265adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
266adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                result = range.start;
267adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
268adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return result;
269adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
270adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
271adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public int getRunLimit(AttributedCharacterIterator.Attribute attribute) {
272adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (attributesAllowed != null
273adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    && !attributesAllowed.contains(attribute)) {
274adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return end;
275adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
276adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            ArrayList<Range> ranges = (ArrayList<Range>) attrString.attributeMap
277adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    .get(attribute);
278adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (ranges == null) {
279adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return end;
280adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
281adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return runLimit(ranges);
282adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
283adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
284adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public int getRunLimit(Set<? extends Attribute> attributes) {
285adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int limit = end;
286adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            Iterator<? extends Attribute> it = attributes.iterator();
287adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            while (it.hasNext()) {
288adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                AttributedCharacterIterator.Attribute attribute = it.next();
289adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                int newLimit = getRunLimit(attribute);
290adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (newLimit < limit) {
291adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    limit = newLimit;
292adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
293adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
294adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return limit;
295adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
296adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
297adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public int getRunStart() {
298adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return getRunStart(getAllAttributeKeys());
299adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
300adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
301adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        private int runStart(List<Range> ranges) {
302adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int result = begin;
303adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            Iterator<Range> it = ranges.iterator();
304adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            while (it.hasNext()) {
305adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                Range range = it.next();
306adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (range.start >= end) {
307adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    break;
308adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
309adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (offset >= range.start && offset < range.end) {
310adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    return inRange(range) ? range.start : result;
311adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                } else if (offset < range.start) {
312adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    break;
313adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
314adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                result = range.end;
315adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
316adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return result;
317adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
318adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
319adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public int getRunStart(AttributedCharacterIterator.Attribute attribute) {
320adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (attributesAllowed != null
321adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    && !attributesAllowed.contains(attribute)) {
322adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return begin;
323adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
324adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            ArrayList<Range> ranges = (ArrayList<Range>) attrString.attributeMap
325adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    .get(attribute);
326adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (ranges == null) {
327adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return begin;
328adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
329adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return runStart(ranges);
330adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
331adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
332adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public int getRunStart(Set<? extends Attribute> attributes) {
333adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int start = begin;
334adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            Iterator<? extends Attribute> it = attributes.iterator();
335adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            while (it.hasNext()) {
336adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                AttributedCharacterIterator.Attribute attribute = it.next();
337adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                int newStart = getRunStart(attribute);
338adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (newStart > start) {
339adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    start = newStart;
340adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
341adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
342adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return start;
343adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
344adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
345adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public char last() {
346adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (begin == end) {
347adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return DONE;
348adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
349adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            offset = end - 1;
350adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return attrString.text.charAt(offset);
351adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
352adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
353adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public char next() {
354adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (offset >= (end - 1)) {
355adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                offset = end;
356adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return DONE;
357adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
358adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return attrString.text.charAt(++offset);
359adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
360adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
361adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public char previous() {
362adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (offset == begin) {
363adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return DONE;
364adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
365adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return attrString.text.charAt(--offset);
366adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
367adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
368adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public char setIndex(int location) {
369adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (location < begin || location > end) {
370adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                throw new IllegalArgumentException();
371adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
372adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            offset = location;
373adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (offset == end) {
374adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return DONE;
375adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
376adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return attrString.text.charAt(offset);
377adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
378adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
379adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
380adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
381adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Constructs an {@code AttributedString} from an {@code
382adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * AttributedCharacterIterator}, which represents attributed text.
3839b354e75f2418e54638e02d153216660b67d01b8Jesse Wilson     *
384adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param iterator
385adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the {@code AttributedCharacterIterator} that contains the text
386adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            for this attributed string.
387adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
388adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public AttributedString(AttributedCharacterIterator iterator) {
389adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (iterator.getBeginIndex() > iterator.getEndIndex()) {
39003c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes            throw new IllegalArgumentException("Invalid substring range");
391adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
3929b354e75f2418e54638e02d153216660b67d01b8Jesse Wilson        StringBuilder buffer = new StringBuilder();
393adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        for (int i = iterator.getBeginIndex(); i < iterator.getEndIndex(); i++) {
394adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            buffer.append(iterator.current());
395adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            iterator.next();
396adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
397adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        text = buffer.toString();
398adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Set<AttributedCharacterIterator.Attribute> attributes = iterator
399adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                .getAllAttributeKeys();
400adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (attributes == null) {
401adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return;
402adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
403adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        attributeMap = new HashMap<Attribute, List<Range>>(
404adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                (attributes.size() * 4 / 3) + 1);
405adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
406adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Iterator<Attribute> it = attributes.iterator();
407adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        while (it.hasNext()) {
408adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            AttributedCharacterIterator.Attribute attribute = it.next();
409adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            iterator.setIndex(0);
410adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            while (iterator.current() != CharacterIterator.DONE) {
411adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                int start = iterator.getRunStart(attribute);
412adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                int limit = iterator.getRunLimit(attribute);
413adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                Object value = iterator.getAttribute(attribute);
414adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (value != null) {
415adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    addAttribute(attribute, value, start, limit);
416adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
417adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                iterator.setIndex(limit);
418adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
419adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
420adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
421adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
422adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private AttributedString(AttributedCharacterIterator iterator, int start,
423adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int end, Set<Attribute> attributes) {
424adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (start < iterator.getBeginIndex() || end > iterator.getEndIndex()
425adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                || start > end) {
426adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IllegalArgumentException();
427adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
428adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
429adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (attributes == null) {
430adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return;
431adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
432adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
4339b354e75f2418e54638e02d153216660b67d01b8Jesse Wilson        StringBuilder buffer = new StringBuilder();
434adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        iterator.setIndex(start);
435adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        while (iterator.getIndex() < end) {
436adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            buffer.append(iterator.current());
437adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            iterator.next();
438adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
439adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        text = buffer.toString();
440adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        attributeMap = new HashMap<Attribute, List<Range>>(
441adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                (attributes.size() * 4 / 3) + 1);
442adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
443adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Iterator<Attribute> it = attributes.iterator();
444adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        while (it.hasNext()) {
445adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            AttributedCharacterIterator.Attribute attribute = it.next();
446adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            iterator.setIndex(start);
447adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            while (iterator.getIndex() < end) {
448adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                Object value = iterator.getAttribute(attribute);
449adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                int runStart = iterator.getRunStart(attribute);
450adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                int limit = iterator.getRunLimit(attribute);
451adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if ((value instanceof Annotation && runStart >= start && limit <= end)
452adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        || (value != null && !(value instanceof Annotation))) {
453adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    addAttribute(attribute, value, (runStart < start ? start
454adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            : runStart)
455adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            - start, (limit > end ? end : limit) - start);
456adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
457adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                iterator.setIndex(limit);
458adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
459adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
460adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
461adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
462adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
463adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Constructs an {@code AttributedString} from a range of the text contained
464adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * in the specified {@code AttributedCharacterIterator}, starting at {@code
465adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * start} and ending at {@code end}. All attributes will be copied to this
466adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * attributed string.
4679b354e75f2418e54638e02d153216660b67d01b8Jesse Wilson     *
468adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param iterator
469adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the {@code AttributedCharacterIterator} that contains the text
470adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            for this attributed string.
471adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param start
472adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the start index of the range of the copied text.
473adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param end
474adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the end index of the range of the copied text.
475adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalArgumentException
4769b354e75f2418e54638e02d153216660b67d01b8Jesse Wilson     *             if {@code start} is less than first index of
477adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             {@code iterator}, {@code end} is greater than the last
478adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             index + 1 in {@code iterator} or if {@code start > end}.
479adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
480adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public AttributedString(AttributedCharacterIterator iterator, int start,
481adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int end) {
482adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this(iterator, start, end, iterator.getAllAttributeKeys());
483adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
484adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
485adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
486adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Constructs an {@code AttributedString} from a range of the text contained
487adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * in the specified {@code AttributedCharacterIterator}, starting at {@code
488adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * start}, ending at {@code end} and it will copy the attributes defined in
489adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * the specified set. If the set is {@code null} then all attributes are
490adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * copied.
4919b354e75f2418e54638e02d153216660b67d01b8Jesse Wilson     *
492adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param iterator
493adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the {@code AttributedCharacterIterator} that contains the text
494adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            for this attributed string.
495adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param start
496adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the start index of the range of the copied text.
497adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param end
498adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the end index of the range of the copied text.
499adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param attributes
500adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the set of attributes that will be copied, or all if it is
501adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            {@code null}.
502adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalArgumentException
5039b354e75f2418e54638e02d153216660b67d01b8Jesse Wilson     *             if {@code start} is less than first index of
5049b354e75f2418e54638e02d153216660b67d01b8Jesse Wilson     *             {@code iterator}, {@code end} is greater than the last index +
505adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             1 in {@code iterator} or if {@code start > end}.
506adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
507adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public AttributedString(AttributedCharacterIterator iterator, int start,
508adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int end, AttributedCharacterIterator.Attribute[] attributes) {
509adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this(iterator, start, end, (attributes == null
510adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                ? new HashSet<Attribute>()
511adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                : new HashSet<Attribute>(Arrays.asList(attributes))));
512adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
513adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
514adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
515adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Creates an {@code AttributedString} from the given text.
5169b354e75f2418e54638e02d153216660b67d01b8Jesse Wilson     *
517adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param value
518adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the text to take as base for this attributed string.
519adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
520adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public AttributedString(String value) {
521adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (value == null) {
52286acc043d3334651ee26c65467d78d6cefedd397Kenny Root            throw new NullPointerException("value == null");
523adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
524adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        text = value;
525adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        attributeMap = new HashMap<Attribute, List<Range>>(11);
526adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
527adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
528adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
529adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Creates an {@code AttributedString} from the given text and the
530adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * attributes. The whole text has the given attributes applied.
5319b354e75f2418e54638e02d153216660b67d01b8Jesse Wilson     *
532adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param value
533adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the text to take as base for this attributed string.
534adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param attributes
535adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the attributes that the text is associated with.
536adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalArgumentException
537adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the length of {@code value} is 0 but the size of {@code
538adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             attributes} is greater than 0.
539adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws NullPointerException
540adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if {@code value} is {@code null}.
541adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
542adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public AttributedString(String value,
543adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            Map<? extends AttributedCharacterIterator.Attribute, ?> attributes) {
544adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (value == null) {
54586acc043d3334651ee26c65467d78d6cefedd397Kenny Root            throw new NullPointerException("value == null");
546adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
547adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (value.length() == 0 && !attributes.isEmpty()) {
54803c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes            throw new IllegalArgumentException("Cannot add attributes to empty string");
549adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
550adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        text = value;
551adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        attributeMap = new HashMap<Attribute, List<Range>>(
552adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                (attributes.size() * 4 / 3) + 1);
553adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Iterator<?> it = attributes.entrySet().iterator();
554adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        while (it.hasNext()) {
555adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            Map.Entry<?, ?> entry = (Map.Entry<?, ?>) it.next();
556adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            ArrayList<Range> ranges = new ArrayList<Range>(1);
557adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            ranges.add(new Range(0, text.length(), entry.getValue()));
558adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            attributeMap.put((AttributedCharacterIterator.Attribute) entry
559adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    .getKey(), ranges);
560adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
561adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
562adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
563adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
564adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Applies a given attribute to this string.
5659b354e75f2418e54638e02d153216660b67d01b8Jesse Wilson     *
566adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param attribute
567adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the attribute that will be applied to this string.
568adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param value
569adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the value of the attribute that will be applied to this
570adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            string.
571adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalArgumentException
572adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the length of this attributed string is 0.
573adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws NullPointerException
574adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if {@code attribute} is {@code null}.
575adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
576b46dab348e2007bc08abaf7ecae34d89a2474e50Elliott Hughes    public void addAttribute(AttributedCharacterIterator.Attribute attribute, Object value) {
577b46dab348e2007bc08abaf7ecae34d89a2474e50Elliott Hughes        if (attribute == null) {
57886acc043d3334651ee26c65467d78d6cefedd397Kenny Root            throw new NullPointerException("attribute == null");
579adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
580adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (text.length() == 0) {
581adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IllegalArgumentException();
582adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
583adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
584adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        List<Range> ranges = attributeMap.get(attribute);
585adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (ranges == null) {
586adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            ranges = new ArrayList<Range>(1);
587adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            attributeMap.put(attribute, ranges);
588adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
589adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            ranges.clear();
590adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
591adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        ranges.add(new Range(0, text.length(), value));
592adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
593adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
594adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
595adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Applies a given attribute to the given range of this string.
5969b354e75f2418e54638e02d153216660b67d01b8Jesse Wilson     *
597adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param attribute
598adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the attribute that will be applied to this string.
599adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param value
600adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the value of the attribute that will be applied to this
601adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            string.
602adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param start
603adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the start of the range where the attribute will be applied.
604adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param end
605adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the end of the range where the attribute will be applied.
606adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalArgumentException
607adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if {@code start < 0}, {@code end} is greater than the length
608adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             of this string, or if {@code start >= end}.
609adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws NullPointerException
610adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if {@code attribute} is {@code null}.
611adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
612adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void addAttribute(AttributedCharacterIterator.Attribute attribute,
613adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            Object value, int start, int end) {
614b46dab348e2007bc08abaf7ecae34d89a2474e50Elliott Hughes        if (attribute == null) {
61586acc043d3334651ee26c65467d78d6cefedd397Kenny Root            throw new NullPointerException("attribute == null");
616adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
617adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (start < 0 || end > text.length() || start >= end) {
618adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IllegalArgumentException();
619adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
620adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
621adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (value == null) {
622adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return;
623adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
624adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
625adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        List<Range> ranges = attributeMap.get(attribute);
626adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (ranges == null) {
627adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            ranges = new ArrayList<Range>(1);
628adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            ranges.add(new Range(start, end, value));
629adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            attributeMap.put(attribute, ranges);
630adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return;
631adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
632adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        ListIterator<Range> it = ranges.listIterator();
633adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        while (it.hasNext()) {
634adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            Range range = it.next();
635adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (end <= range.start) {
636adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                it.previous();
637adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                break;
638adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else if (start < range.end
639adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    || (start == range.end && value.equals(range.value))) {
640adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                Range r1 = null, r3;
641adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                it.remove();
642adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                r1 = new Range(range.start, start, range.value);
643adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                r3 = new Range(end, range.end, range.value);
644adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
645adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                while (end > range.end && it.hasNext()) {
646adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    range = it.next();
647adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    if (end <= range.end) {
648adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        if (end > range.start
649adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                || (end == range.start && value.equals(range.value))) {
650adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            it.remove();
651adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            r3 = new Range(end, range.end, range.value);
652adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            break;
653adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        }
654adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    } else {
655adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        it.remove();
656adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
657adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
658adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
659adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (value.equals(r1.value)) {
660adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    if (value.equals(r3.value)) {
661adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        it.add(new Range(r1.start < start ? r1.start : start,
662adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                r3.end > end ? r3.end : end, r1.value));
663adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    } else {
664adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        it.add(new Range(r1.start < start ? r1.start : start,
665adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                end, r1.value));
666adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        if (r3.start < r3.end) {
667adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            it.add(r3);
668adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        }
669adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
670adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                } else {
671adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    if (value.equals(r3.value)) {
672adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        if (r1.start < r1.end) {
673adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            it.add(r1);
674adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        }
675adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        it.add(new Range(start, r3.end > end ? r3.end : end,
676adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                r3.value));
677adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    } else {
678adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        if (r1.start < r1.end) {
679adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            it.add(r1);
680adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        }
681adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        it.add(new Range(start, end, value));
682adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        if (r3.start < r3.end) {
683adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            it.add(r3);
684adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        }
685adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
686adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
687adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return;
688adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
689adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
690adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        it.add(new Range(start, end, value));
691adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
692adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
693adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
694adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Applies a given set of attributes to the given range of the string.
6959b354e75f2418e54638e02d153216660b67d01b8Jesse Wilson     *
696adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param attributes
697adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the set of attributes that will be applied to this string.
698adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param start
699adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the start of the range where the attribute will be applied.
700adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param end
701adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the end of the range where the attribute will be applied.
702adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalArgumentException
703adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if {@code start < 0}, {@code end} is greater than the length
704adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             of this string, or if {@code start >= end}.
705adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
706adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void addAttributes(
707adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            Map<? extends AttributedCharacterIterator.Attribute, ?> attributes,
708adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int start, int end) {
709adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Iterator<?> it = attributes.entrySet().iterator();
710adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        while (it.hasNext()) {
711adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            Map.Entry<?, ?> entry = (Map.Entry<?, ?>) it.next();
712adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            addAttribute(
713adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    (AttributedCharacterIterator.Attribute) entry.getKey(),
714adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    entry.getValue(), start, end);
715adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
716adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
717adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
718adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
719adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns an {@code AttributedCharacterIterator} that gives access to the
720adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * complete content of this attributed string.
7219b354e75f2418e54638e02d153216660b67d01b8Jesse Wilson     *
722adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the newly created {@code AttributedCharacterIterator}.
723adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
724adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public AttributedCharacterIterator getIterator() {
725adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return new AttributedIterator(this);
726adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
727adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
728adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
729adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns an {@code AttributedCharacterIterator} that gives access to the
730adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * complete content of this attributed string. Only attributes contained in
731adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@code attributes} are available from this iterator if they are defined
732adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * for this text.
7339b354e75f2418e54638e02d153216660b67d01b8Jesse Wilson     *
734adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param attributes
735adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the array containing attributes that will be in the new
736adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            iterator if they are defined for this text.
737adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the newly created {@code AttributedCharacterIterator}.
738adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
739adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public AttributedCharacterIterator getIterator(
740adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            AttributedCharacterIterator.Attribute[] attributes) {
741adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return new AttributedIterator(this, attributes, 0, text.length());
742adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
743adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
744adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
745adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns an {@code AttributedCharacterIterator} that gives access to the
746adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * contents of this attributed string starting at index {@code start} up to
747adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * index {@code end}. Only attributes contained in {@code attributes} are
748adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * available from this iterator if they are defined for this text.
7499b354e75f2418e54638e02d153216660b67d01b8Jesse Wilson     *
750adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param attributes
751adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the array containing attributes that will be in the new
752adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            iterator if they are defined for this text.
753adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param start
754adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the start index of the iterator on the underlying text.
755adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param end
756adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the end index of the iterator on the underlying text.
757adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the newly created {@code AttributedCharacterIterator}.
758adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
759adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public AttributedCharacterIterator getIterator(
760adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            AttributedCharacterIterator.Attribute[] attributes, int start,
761adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int end) {
762adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return new AttributedIterator(this, attributes, start, end);
763adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
764adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
765