001 /*
002 * Copyright 2009 - 2009 JEuclid, http://jeuclid.sf.net
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 /* $Id: MultiAttributedCharacterIterator.java,v 344ccd357471 2009/09/10 14:15:11 max $ */
018
019 package net.sourceforge.jeuclid.elements.support.text;
020
021 import java.text.AttributedCharacterIterator;
022 import java.text.CharacterIterator;
023 import java.util.ArrayList;
024 import java.util.HashSet;
025 import java.util.List;
026 import java.util.Map;
027 import java.util.Set;
028
029 /**
030 * Joins multiple {@link AttributedCharacterIterator}s into one.
031 *
032 * @version $Revision: 344ccd357471 $
033 */
034 public class MultiAttributedCharacterIterator implements
035 AttributedCharacterIterator {
036
037 private final List<AttributedCharacterIterator> realIterators = new ArrayList<AttributedCharacterIterator>();
038
039 private int currentList;
040
041 /**
042 * Default constructor.
043 */
044 public MultiAttributedCharacterIterator() {
045 // nothing to do;
046 }
047
048 // CHECKSTYLE:OFF Clone is disabled.
049 @Override
050 public Object clone() {
051 throw new UnsupportedOperationException();
052 }
053
054 // CHECKSTYLE: ON
055
056 /**
057 * Adds a new CharacterIterator
058 *
059 * @param aci
060 * the new CharacterIterator to add to the list.
061 */
062 public void appendAttributedCharacterIterator(
063 final AttributedCharacterIterator aci) {
064 this.realIterators.add(aci);
065 this.first();
066 }
067
068 private int sumUpToNotIncluding(final int limit) {
069 int offset = 0;
070 for (int i = 0; i < limit; i++) {
071 final AttributedCharacterIterator ci = this.realIterators.get(i);
072 offset += ci.getEndIndex() - ci.getBeginIndex();
073 }
074 return offset;
075 }
076
077 private int currentOffset() {
078 int offset = this.sumUpToNotIncluding(this.currentList);
079 offset -= this.realIterators.get(this.currentList).getBeginIndex();
080 return offset;
081 }
082
083 /** {@inheritDoc} */
084 public Set<Attribute> getAllAttributeKeys() {
085 final Set<Attribute> retVal = new HashSet<Attribute>();
086 for (final AttributedCharacterIterator ri : this.realIterators) {
087 retVal.addAll(ri.getAllAttributeKeys());
088 }
089 return retVal;
090 }
091
092 /** {@inheritDoc} */
093 public Object getAttribute(final Attribute attribute) {
094 return this.realIterators.get(this.currentList).getAttribute(attribute);
095 }
096
097 /** {@inheritDoc} */
098 public Map<Attribute, Object> getAttributes() {
099 return this.realIterators.get(this.currentList).getAttributes();
100 }
101
102 /** {@inheritDoc} */
103 public int getRunLimit() {
104 return this.realIterators.get(this.currentList).getRunLimit()
105 + this.currentOffset();
106 }
107
108 /** {@inheritDoc} */
109 public int getRunLimit(final Attribute attribute) {
110 return this.realIterators.get(this.currentList).getRunLimit(attribute)
111 + this.currentOffset();
112 }
113
114 /** {@inheritDoc} */
115 public int getRunLimit(final Set<? extends Attribute> attributes) {
116 return this.realIterators.get(this.currentList).getRunLimit(attributes)
117 + this.currentOffset();
118 }
119
120 /** {@inheritDoc} */
121 public int getRunStart() {
122 return this.realIterators.get(this.currentList).getRunStart()
123 + this.currentOffset();
124 }
125
126 /** {@inheritDoc} */
127 public int getRunStart(final Attribute attribute) {
128 return this.realIterators.get(this.currentList).getRunStart(attribute)
129 + this.currentOffset();
130 }
131
132 /** {@inheritDoc} */
133 public int getRunStart(final Set<? extends Attribute> attributes) {
134 return this.realIterators.get(this.currentList).getRunStart(attributes)
135 + this.currentOffset();
136 }
137
138 /** {@inheritDoc} */
139 public char current() {
140 return this.realIterators.get(this.currentList).current();
141 }
142
143 /** {@inheritDoc} */
144 public char first() {
145 this.currentList = 0;
146 return this.realIterators.get(this.currentList).first();
147 }
148
149 /** {@inheritDoc} */
150 public int getBeginIndex() {
151 return 0;
152 }
153
154 /** {@inheritDoc} */
155 public int getEndIndex() {
156 return this.sumUpToNotIncluding(this.realIterators.size());
157 }
158
159 /** {@inheritDoc} */
160 public int getIndex() {
161 return this.currentOffset()
162 + this.realIterators.get(this.currentList).getIndex();
163 }
164
165 /** {@inheritDoc} */
166 public char last() {
167 this.currentList = this.realIterators.size() - 1;
168 return this.realIterators.get(this.currentList).last();
169 }
170
171 /** {@inheritDoc} */
172 public char next() {
173 char c = this.realIterators.get(this.currentList).next();
174 while ((c == CharacterIterator.DONE)
175 && (this.currentList < this.realIterators.size() - 1)) {
176 this.currentList++;
177 c = this.realIterators.get(this.currentList).first();
178 }
179 return c;
180 }
181
182 /** {@inheritDoc} */
183 public char previous() {
184 char c = this.realIterators.get(this.currentList).previous();
185 while ((c == CharacterIterator.DONE) && (this.currentList > 0)) {
186 this.currentList--;
187 c = this.realIterators.get(this.currentList).previous();
188 }
189 return c;
190 }
191
192 /** {@inheritDoc} */
193 public char setIndex(final int position) {
194 int prev = 0;
195 int offset = 0;
196 for (int i = 0; i < this.realIterators.size(); i++) {
197 final AttributedCharacterIterator ci = this.realIterators.get(i);
198 prev = offset;
199 final int beginIndex = ci.getBeginIndex();
200 offset += ci.getEndIndex() - beginIndex;
201 if (((prev <= position) && (offset > position))
202 || ((offset == position) && (i == this.realIterators.size() - 1))) {
203 this.currentList = i;
204 return ci.setIndex(beginIndex + position - prev);
205 }
206 }
207 throw new IllegalArgumentException();
208 }
209 }