151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski/* 251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved. 351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * This code is free software; you can redistribute it and/or modify it 651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * under the terms of the GNU General Public License version 2 only, as 751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * published by the Free Software Foundation. Oracle designates this 851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * particular file as subject to the "Classpath" exception as provided 951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * by Oracle in the LICENSE file that accompanied this code. 1051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 1151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * This code is distributed in the hope that it will be useful, but WITHOUT 1251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * version 2 for more details (a copy is included in the LICENSE file that 1551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * accompanied this code). 1651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 1751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * You should have received a copy of the GNU General Public License version 1851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 2 along with this work; if not, write to the Free Software Foundation, 1951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 2051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 2151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * or visit www.oracle.com if you need additional information or have any 2351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * questions. 2451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 2551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 2651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskipackage java.text; 2751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 2851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.*; 2951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.text.AttributedCharacterIterator.Attribute; 3051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 3151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski/** 3251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * An AttributedString holds text and related attribute information. It 3351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * may be used as the actual data storage in some cases where a text 3451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * reader wants to access attributed text through the AttributedCharacterIterator 3551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * interface. 3651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 3751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <p> 3851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * An attribute is a key/value pair, identified by the key. No two 3951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * attributes on a given character can have the same key. 4051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 4151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <p>The values for an attribute are immutable, or must not be mutated 4251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * by clients or storage. They are always passed by reference, and not 4351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * cloned. 4451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 4551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @see AttributedCharacterIterator 4651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @see Annotation 4751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @since 1.2 4851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 4951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 5051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskipublic class AttributedString { 5151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 5251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // since there are no vectors of int, we have to use arrays. 5351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // We allocate them in chunks of 10 elements so we don't have to allocate all the time. 5451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private static final int ARRAY_SIZE_INCREMENT = 10; 5551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 5651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // field holding the text 5751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski String text; 5851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 5951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // fields holding run attribute information 6051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // run attributes are organized by run 6151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int runArraySize; // current size of the arrays 6251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int runCount; // actual number of runs, <= runArraySize 6351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int runStarts[]; // start index for each run 6451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Vector runAttributes[]; // vector of attribute keys for each run 6551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Vector runAttributeValues[]; // parallel vector of attribute values for each run 6651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 6751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 6851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Constructs an AttributedString instance with the given 6951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * AttributedCharacterIterators. 7051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 7151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param iterators AttributedCharacterIterators to construct 7251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * AttributedString from. 7351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @throws NullPointerException if iterators is null 7451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 7551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski AttributedString(AttributedCharacterIterator[] iterators) { 7651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (iterators == null) { 7751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski throw new NullPointerException("Iterators must not be null"); 7851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 7951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (iterators.length == 0) { 8051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski text = ""; 8151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 8251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski else { 8351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // Build the String contents 8451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski StringBuffer buffer = new StringBuffer(); 8551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski for (int counter = 0; counter < iterators.length; counter++) { 8651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski appendContents(buffer, iterators[counter]); 8751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 8851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 8951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski text = buffer.toString(); 9051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 9151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (text.length() > 0) { 9251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // Determine the runs, creating a new run when the attributes 9351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // differ. 9451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int offset = 0; 9551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Map last = null; 9651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 9751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski for (int counter = 0; counter < iterators.length; counter++) { 9851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski AttributedCharacterIterator iterator = iterators[counter]; 9951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int start = iterator.getBeginIndex(); 10051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int end = iterator.getEndIndex(); 10151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int index = start; 10251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 10351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski while (index < end) { 10451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski iterator.setIndex(index); 10551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 10651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Map attrs = iterator.getAttributes(); 10751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 10851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (mapsDiffer(last, attrs)) { 10951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski setAttributes(attrs, index - start + offset); 11051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 11151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski last = attrs; 11251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski index = iterator.getRunLimit(); 11351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 11451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski offset += (end - start); 11551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 11651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 11751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 11851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 11951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 12051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 12151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Constructs an AttributedString instance with the given text. 12251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param text The text for this attributed string. 12351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @exception NullPointerException if <code>text</code> is null. 12451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 12551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public AttributedString(String text) { 12651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (text == null) { 12751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski throw new NullPointerException(); 12851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 12951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski this.text = text; 13051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 13151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 13251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 13351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Constructs an AttributedString instance with the given text and attributes. 13451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param text The text for this attributed string. 13551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param attributes The attributes that apply to the entire string. 13651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @exception NullPointerException if <code>text</code> or 13751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <code>attributes</code> is null. 13851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @exception IllegalArgumentException if the text has length 0 13951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * and the attributes parameter is not an empty Map (attributes 14051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * cannot be applied to a 0-length range). 14151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 14251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public AttributedString(String text, 14351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Map<? extends Attribute, ?> attributes) 14451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski { 14551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (text == null || attributes == null) { 14651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski throw new NullPointerException(); 14751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 14851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski this.text = text; 14951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 15051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (text.length() == 0) { 15151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (attributes.isEmpty()) 15251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return; 15351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski throw new IllegalArgumentException("Can't add attribute to 0-length text"); 15451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 15551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 15651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int attributeCount = attributes.size(); 15751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (attributeCount > 0) { 15851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski createRunAttributeDataVectors(); 15951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Vector newRunAttributes = new Vector(attributeCount); 16051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Vector newRunAttributeValues = new Vector(attributeCount); 16151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runAttributes[0] = newRunAttributes; 16251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runAttributeValues[0] = newRunAttributeValues; 16351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Iterator iterator = attributes.entrySet().iterator(); 16451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski while (iterator.hasNext()) { 16551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Map.Entry entry = (Map.Entry) iterator.next(); 16651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski newRunAttributes.addElement(entry.getKey()); 16751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski newRunAttributeValues.addElement(entry.getValue()); 16851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 16951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 17051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 17151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 17251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 17351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Constructs an AttributedString instance with the given attributed 17451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * text represented by AttributedCharacterIterator. 17551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param text The text for this attributed string. 17651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @exception NullPointerException if <code>text</code> is null. 17751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 17851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public AttributedString(AttributedCharacterIterator text) { 17951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // If performance is critical, this constructor should be 18051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // implemented here rather than invoking the constructor for a 18151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // subrange. We can avoid some range checking in the loops. 18251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski this(text, text.getBeginIndex(), text.getEndIndex(), null); 18351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 18451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 18551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 18651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Constructs an AttributedString instance with the subrange of 18751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * the given attributed text represented by 18851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * AttributedCharacterIterator. If the given range produces an 18951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * empty text, all attributes will be discarded. Note that any 19051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * attributes wrapped by an Annotation object are discarded for a 19151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * subrange of the original attribute range. 19251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 19351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param text The text for this attributed string. 19451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param beginIndex Index of the first character of the range. 19551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param endIndex Index of the character following the last character 19651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * of the range. 19751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @exception NullPointerException if <code>text</code> is null. 19851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @exception IllegalArgumentException if the subrange given by 19951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * beginIndex and endIndex is out of the text range. 20051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @see java.text.Annotation 20151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 20251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public AttributedString(AttributedCharacterIterator text, 20351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int beginIndex, 20451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int endIndex) { 20551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski this(text, beginIndex, endIndex, null); 20651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 20751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 20851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 20951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Constructs an AttributedString instance with the subrange of 21051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * the given attributed text represented by 21151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * AttributedCharacterIterator. Only attributes that match the 21251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * given attributes will be incorporated into the instance. If the 21351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * given range produces an empty text, all attributes will be 21451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * discarded. Note that any attributes wrapped by an Annotation 21551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * object are discarded for a subrange of the original attribute 21651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * range. 21751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 21851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param text The text for this attributed string. 21951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param beginIndex Index of the first character of the range. 22051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param endIndex Index of the character following the last character 22151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * of the range. 22251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param attributes Specifies attributes to be extracted 22351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * from the text. If null is specified, all available attributes will 22451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * be used. 22551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @exception NullPointerException if <code>text</code> is null. 22651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @exception IllegalArgumentException if the subrange given by 22751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * beginIndex and endIndex is out of the text range. 22851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @see java.text.Annotation 22951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 23051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public AttributedString(AttributedCharacterIterator text, 23151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int beginIndex, 23251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int endIndex, 23351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Attribute[] attributes) { 23451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (text == null) { 23551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski throw new NullPointerException(); 23651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 23751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 23851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // Validate the given subrange 23951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int textBeginIndex = text.getBeginIndex(); 24051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int textEndIndex = text.getEndIndex(); 24151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (beginIndex < textBeginIndex || endIndex > textEndIndex || beginIndex > endIndex) 24251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski throw new IllegalArgumentException("Invalid substring range"); 24351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 24451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // Copy the given string 24551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski StringBuffer textBuffer = new StringBuffer(); 24651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski text.setIndex(beginIndex); 24751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski for (char c = text.current(); text.getIndex() < endIndex; c = text.next()) 24851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski textBuffer.append(c); 24951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski this.text = textBuffer.toString(); 25051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 25151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (beginIndex == endIndex) 25251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return; 25351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 25451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // Select attribute keys to be taken care of 25551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski HashSet keys = new HashSet(); 25651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (attributes == null) { 25751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski keys.addAll(text.getAllAttributeKeys()); 25851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } else { 25951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski for (int i = 0; i < attributes.length; i++) 26051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski keys.add(attributes[i]); 26151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski keys.retainAll(text.getAllAttributeKeys()); 26251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 26351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (keys.isEmpty()) 26451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return; 26551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 26651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // Get and set attribute runs for each attribute name. Need to 26751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // scan from the top of the text so that we can discard any 26851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // Annotation that is no longer applied to a subset text segment. 26951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Iterator itr = keys.iterator(); 27051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski while (itr.hasNext()) { 27151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Attribute attributeKey = (Attribute)itr.next(); 27251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski text.setIndex(textBeginIndex); 27351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski while (text.getIndex() < endIndex) { 27451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int start = text.getRunStart(attributeKey); 27551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int limit = text.getRunLimit(attributeKey); 27651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Object value = text.getAttribute(attributeKey); 27751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 27851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (value != null) { 27951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (value instanceof Annotation) { 28051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (start >= beginIndex && limit <= endIndex) { 28151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski addAttribute(attributeKey, value, start - beginIndex, limit - beginIndex); 28251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } else { 28351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (limit > endIndex) 28451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski break; 28551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 28651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } else { 28751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // if the run is beyond the given (subset) range, we 28851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // don't need to process further. 28951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (start >= endIndex) 29051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski break; 29151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (limit > beginIndex) { 29251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // attribute is applied to any subrange 29351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (start < beginIndex) 29451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski start = beginIndex; 29551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (limit > endIndex) 29651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski limit = endIndex; 29751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (start != limit) { 29851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski addAttribute(attributeKey, value, start - beginIndex, limit - beginIndex); 29951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 30051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 30151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 30251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 30351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski text.setIndex(limit); 30451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 30551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 30651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 30751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 30851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 30951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Adds an attribute to the entire string. 31051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param attribute the attribute key 31151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param value the value of the attribute; may be null 31251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @exception NullPointerException if <code>attribute</code> is null. 31351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @exception IllegalArgumentException if the AttributedString has length 0 31451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * (attributes cannot be applied to a 0-length range). 31551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 31651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public void addAttribute(Attribute attribute, Object value) { 31751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 31851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (attribute == null) { 31951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski throw new NullPointerException(); 32051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 32151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 32251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int len = length(); 32351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (len == 0) { 32451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski throw new IllegalArgumentException("Can't add attribute to 0-length text"); 32551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 32651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 32751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski addAttributeImpl(attribute, value, 0, len); 32851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 32951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 33051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 33151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Adds an attribute to a subrange of the string. 33251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param attribute the attribute key 33351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param value The value of the attribute. May be null. 33451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param beginIndex Index of the first character of the range. 33551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param endIndex Index of the character following the last character of the range. 33651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @exception NullPointerException if <code>attribute</code> is null. 33751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @exception IllegalArgumentException if beginIndex is less then 0, endIndex is 33851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * greater than the length of the string, or beginIndex and endIndex together don't 33951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * define a non-empty subrange of the string. 34051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 34151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public void addAttribute(Attribute attribute, Object value, 34251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int beginIndex, int endIndex) { 34351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 34451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (attribute == null) { 34551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski throw new NullPointerException(); 34651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 34751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 34851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (beginIndex < 0 || endIndex > length() || beginIndex >= endIndex) { 34951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski throw new IllegalArgumentException("Invalid substring range"); 35051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 35151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 35251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski addAttributeImpl(attribute, value, beginIndex, endIndex); 35351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 35451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 35551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 35651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Adds a set of attributes to a subrange of the string. 35751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param attributes The attributes to be added to the string. 35851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param beginIndex Index of the first character of the range. 35951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param endIndex Index of the character following the last 36051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * character of the range. 36151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @exception NullPointerException if <code>attributes</code> is null. 36251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @exception IllegalArgumentException if beginIndex is less then 36351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 0, endIndex is greater than the length of the string, or 36451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * beginIndex and endIndex together don't define a non-empty 36551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * subrange of the string and the attributes parameter is not an 36651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * empty Map. 36751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 36851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public void addAttributes(Map<? extends Attribute, ?> attributes, 36951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int beginIndex, int endIndex) 37051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski { 37151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (attributes == null) { 37251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski throw new NullPointerException(); 37351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 37451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 37551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (beginIndex < 0 || endIndex > length() || beginIndex > endIndex) { 37651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski throw new IllegalArgumentException("Invalid substring range"); 37751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 37851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (beginIndex == endIndex) { 37951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (attributes.isEmpty()) 38051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return; 38151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski throw new IllegalArgumentException("Can't add attribute to 0-length text"); 38251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 38351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 38451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // make sure we have run attribute data vectors 38551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (runCount == 0) { 38651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski createRunAttributeDataVectors(); 38751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 38851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 38951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // break up runs if necessary 39051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int beginRunIndex = ensureRunBreak(beginIndex); 39151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int endRunIndex = ensureRunBreak(endIndex); 39251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 39351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Iterator iterator = attributes.entrySet().iterator(); 39451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski while (iterator.hasNext()) { 39551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Map.Entry entry = (Map.Entry) iterator.next(); 39651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski addAttributeRunData((Attribute) entry.getKey(), entry.getValue(), beginRunIndex, endRunIndex); 39751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 39851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 39951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 40051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private synchronized void addAttributeImpl(Attribute attribute, Object value, 40151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int beginIndex, int endIndex) { 40251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 40351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // make sure we have run attribute data vectors 40451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (runCount == 0) { 40551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski createRunAttributeDataVectors(); 40651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 40751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 40851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // break up runs if necessary 40951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int beginRunIndex = ensureRunBreak(beginIndex); 41051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int endRunIndex = ensureRunBreak(endIndex); 41151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 41251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski addAttributeRunData(attribute, value, beginRunIndex, endRunIndex); 41351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 41451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 41551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private final void createRunAttributeDataVectors() { 41651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // use temporary variables so things remain consistent in case of an exception 41751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int newRunStarts[] = new int[ARRAY_SIZE_INCREMENT]; 41851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Vector newRunAttributes[] = new Vector[ARRAY_SIZE_INCREMENT]; 41951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Vector newRunAttributeValues[] = new Vector[ARRAY_SIZE_INCREMENT]; 42051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runStarts = newRunStarts; 42151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runAttributes = newRunAttributes; 42251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runAttributeValues = newRunAttributeValues; 42351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runArraySize = ARRAY_SIZE_INCREMENT; 42451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runCount = 1; // assume initial run starting at index 0 42551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 42651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 42751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // ensure there's a run break at offset, return the index of the run 42851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private final int ensureRunBreak(int offset) { 42951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return ensureRunBreak(offset, true); 43051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 43151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 43251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 43351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Ensures there is a run break at offset, returning the index of 43451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * the run. If this results in splitting a run, two things can happen: 43551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <ul> 43651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <li>If copyAttrs is true, the attributes from the existing run 43751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * will be placed in both of the newly created runs. 43851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <li>If copyAttrs is false, the attributes from the existing run 43951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * will NOT be copied to the run to the right (>= offset) of the break, 44051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * but will exist on the run to the left (< offset). 44151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * </ul> 44251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 44351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private final int ensureRunBreak(int offset, boolean copyAttrs) { 44451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (offset == length()) { 44551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return runCount; 44651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 44751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 44851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // search for the run index where this offset should be 44951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int runIndex = 0; 45051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski while (runIndex < runCount && runStarts[runIndex] < offset) { 45151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runIndex++; 45251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 45351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 45451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // if the offset is at a run start already, we're done 45551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (runIndex < runCount && runStarts[runIndex] == offset) { 45651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return runIndex; 45751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 45851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 45951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // we'll have to break up a run 46051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // first, make sure we have enough space in our arrays 46151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (runCount == runArraySize) { 46251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int newArraySize = runArraySize + ARRAY_SIZE_INCREMENT; 46351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int newRunStarts[] = new int[newArraySize]; 46451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Vector newRunAttributes[] = new Vector[newArraySize]; 46551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Vector newRunAttributeValues[] = new Vector[newArraySize]; 46651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski for (int i = 0; i < runArraySize; i++) { 46751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski newRunStarts[i] = runStarts[i]; 46851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski newRunAttributes[i] = runAttributes[i]; 46951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski newRunAttributeValues[i] = runAttributeValues[i]; 47051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 47151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runStarts = newRunStarts; 47251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runAttributes = newRunAttributes; 47351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runAttributeValues = newRunAttributeValues; 47451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runArraySize = newArraySize; 47551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 47651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 47751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // make copies of the attribute information of the old run that the new one used to be part of 47851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // use temporary variables so things remain consistent in case of an exception 47951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Vector newRunAttributes = null; 48051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Vector newRunAttributeValues = null; 48151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 48251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (copyAttrs) { 48351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Vector oldRunAttributes = runAttributes[runIndex - 1]; 48451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Vector oldRunAttributeValues = runAttributeValues[runIndex - 1]; 48551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (oldRunAttributes != null) { 48651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski newRunAttributes = (Vector) oldRunAttributes.clone(); 48751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 48851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (oldRunAttributeValues != null) { 48951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski newRunAttributeValues = (Vector) oldRunAttributeValues.clone(); 49051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 49151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 49251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 49351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // now actually break up the run 49451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runCount++; 49551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski for (int i = runCount - 1; i > runIndex; i--) { 49651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runStarts[i] = runStarts[i - 1]; 49751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runAttributes[i] = runAttributes[i - 1]; 49851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runAttributeValues[i] = runAttributeValues[i - 1]; 49951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 50051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runStarts[runIndex] = offset; 50151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runAttributes[runIndex] = newRunAttributes; 50251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runAttributeValues[runIndex] = newRunAttributeValues; 50351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 50451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return runIndex; 50551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 50651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 50751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // add the attribute attribute/value to all runs where beginRunIndex <= runIndex < endRunIndex 50851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private void addAttributeRunData(Attribute attribute, Object value, 50951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int beginRunIndex, int endRunIndex) { 51051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 51151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski for (int i = beginRunIndex; i < endRunIndex; i++) { 51251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int keyValueIndex = -1; // index of key and value in our vectors; assume we don't have an entry yet 51351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (runAttributes[i] == null) { 51451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Vector newRunAttributes = new Vector(); 51551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Vector newRunAttributeValues = new Vector(); 51651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runAttributes[i] = newRunAttributes; 51751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runAttributeValues[i] = newRunAttributeValues; 51851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } else { 51951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // check whether we have an entry already 52051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski keyValueIndex = runAttributes[i].indexOf(attribute); 52151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 52251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 52351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (keyValueIndex == -1) { 52451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // create new entry 52551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int oldSize = runAttributes[i].size(); 52651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runAttributes[i].addElement(attribute); 52751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski try { 52851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runAttributeValues[i].addElement(value); 52951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 53051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski catch (Exception e) { 53151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runAttributes[i].setSize(oldSize); 53251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runAttributeValues[i].setSize(oldSize); 53351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 53451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } else { 53551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // update existing entry 53651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runAttributeValues[i].set(keyValueIndex, value); 53751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 53851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 53951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 54051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 54151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 54251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Creates an AttributedCharacterIterator instance that provides access to the entire contents of 54351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * this string. 54451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 54551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @return An iterator providing access to the text and its attributes. 54651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 54751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public AttributedCharacterIterator getIterator() { 54851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return getIterator(null, 0, length()); 54951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 55051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 55151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 55251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Creates an AttributedCharacterIterator instance that provides access to 55351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * selected contents of this string. 55451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Information about attributes not listed in attributes that the 55551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * implementor may have need not be made accessible through the iterator. 55651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * If the list is null, all available attribute information should be made 55751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * accessible. 55851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 55951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param attributes a list of attributes that the client is interested in 56051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @return an iterator providing access to the entire text and its selected attributes 56151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 56251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public AttributedCharacterIterator getIterator(Attribute[] attributes) { 56351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return getIterator(attributes, 0, length()); 56451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 56551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 56651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 56751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Creates an AttributedCharacterIterator instance that provides access to 56851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * selected contents of this string. 56951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Information about attributes not listed in attributes that the 57051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * implementor may have need not be made accessible through the iterator. 57151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * If the list is null, all available attribute information should be made 57251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * accessible. 57351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 57451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param attributes a list of attributes that the client is interested in 57551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param beginIndex the index of the first character 57651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param endIndex the index of the character following the last character 57751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @return an iterator providing access to the text and its attributes 57851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @exception IllegalArgumentException if beginIndex is less then 0, 57951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * endIndex is greater than the length of the string, or beginIndex is 58051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * greater than endIndex. 58151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 58251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public AttributedCharacterIterator getIterator(Attribute[] attributes, int beginIndex, int endIndex) { 58351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return new AttributedStringIterator(attributes, beginIndex, endIndex); 58451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 58551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 58651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // all (with the exception of length) reading operations are private, 58751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // since AttributedString instances are accessed through iterators. 58851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 58951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // length is package private so that CharacterIteratorFieldDelegate can 59051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // access it without creating an AttributedCharacterIterator. 59151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int length() { 59251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return text.length(); 59351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 59451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 59551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private char charAt(int index) { 59651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return text.charAt(index); 59751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 59851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 59951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private synchronized Object getAttribute(Attribute attribute, int runIndex) { 60051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Vector currentRunAttributes = runAttributes[runIndex]; 60151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Vector currentRunAttributeValues = runAttributeValues[runIndex]; 60251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (currentRunAttributes == null) { 60351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return null; 60451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 60551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int attributeIndex = currentRunAttributes.indexOf(attribute); 60651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (attributeIndex != -1) { 60751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return currentRunAttributeValues.elementAt(attributeIndex); 60851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 60951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski else { 61051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return null; 61151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 61251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 61351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 61451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // gets an attribute value, but returns an annotation only if it's range does not extend outside the range beginIndex..endIndex 61551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private Object getAttributeCheckRange(Attribute attribute, int runIndex, int beginIndex, int endIndex) { 61651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Object value = getAttribute(attribute, runIndex); 61751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (value instanceof Annotation) { 61851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // need to check whether the annotation's range extends outside the iterator's range 61951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (beginIndex > 0) { 62051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int currIndex = runIndex; 62151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int runStart = runStarts[currIndex]; 62251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski while (runStart >= beginIndex && 62351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski valuesMatch(value, getAttribute(attribute, currIndex - 1))) { 62451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski currIndex--; 62551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runStart = runStarts[currIndex]; 62651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 62751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (runStart < beginIndex) { 62851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // annotation's range starts before iterator's range 62951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return null; 63051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 63151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 63251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int textLength = length(); 63351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (endIndex < textLength) { 63451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int currIndex = runIndex; 63551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int runLimit = (currIndex < runCount - 1) ? runStarts[currIndex + 1] : textLength; 63651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski while (runLimit <= endIndex && 63751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski valuesMatch(value, getAttribute(attribute, currIndex + 1))) { 63851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski currIndex++; 63951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runLimit = (currIndex < runCount - 1) ? runStarts[currIndex + 1] : textLength; 64051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 64151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (runLimit > endIndex) { 64251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // annotation's range ends after iterator's range 64351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return null; 64451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 64551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 64651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // annotation's range is subrange of iterator's range, 64751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // so we can return the value 64851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 64951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return value; 65051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 65151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 65251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // returns whether all specified attributes have equal values in the runs with the given indices 65351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private boolean attributeValuesMatch(Set attributes, int runIndex1, int runIndex2) { 65451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Iterator iterator = attributes.iterator(); 65551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski while (iterator.hasNext()) { 65651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Attribute key = (Attribute) iterator.next(); 65751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (!valuesMatch(getAttribute(key, runIndex1), getAttribute(key, runIndex2))) { 65851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return false; 65951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 66051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 66151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return true; 66251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 66351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 66451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // returns whether the two objects are either both null or equal 66551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private final static boolean valuesMatch(Object value1, Object value2) { 66651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (value1 == null) { 66751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return value2 == null; 66851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } else { 66951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return value1.equals(value2); 67051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 67151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 67251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 67351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 67451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Appends the contents of the CharacterIterator iterator into the 67551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * StringBuffer buf. 67651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 67751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private final void appendContents(StringBuffer buf, 67851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski CharacterIterator iterator) { 67951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int index = iterator.getBeginIndex(); 68051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int end = iterator.getEndIndex(); 68151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 68251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski while (index < end) { 68351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski iterator.setIndex(index++); 68451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski buf.append(iterator.current()); 68551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 68651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 68751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 68851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 68951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Sets the attributes for the range from offset to the next run break 69051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * (typically the end of the text) to the ones specified in attrs. 69151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * This is only meant to be called from the constructor! 69251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 69351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private void setAttributes(Map attrs, int offset) { 69451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (runCount == 0) { 69551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski createRunAttributeDataVectors(); 69651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 69751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 69851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int index = ensureRunBreak(offset, false); 69951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int size; 70051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 70151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (attrs != null && (size = attrs.size()) > 0) { 70251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Vector runAttrs = new Vector(size); 70351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Vector runValues = new Vector(size); 70451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Iterator iterator = attrs.entrySet().iterator(); 70551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 70651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski while (iterator.hasNext()) { 70751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Map.Entry entry = (Map.Entry)iterator.next(); 70851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 70951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runAttrs.add(entry.getKey()); 71051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runValues.add(entry.getValue()); 71151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 71251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runAttributes[index] = runAttrs; 71351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runAttributeValues[index] = runValues; 71451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 71551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 71651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 71751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 71851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Returns true if the attributes specified in last and attrs differ. 71951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 72051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private static boolean mapsDiffer(Map last, Map attrs) { 72151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (last == null) { 72251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return (attrs != null && attrs.size() > 0); 72351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 72451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return (!last.equals(attrs)); 72551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 72651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 72751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 72851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // the iterator class associated with this string class 72951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 73051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski final private class AttributedStringIterator implements AttributedCharacterIterator { 73151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 73251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // note on synchronization: 73351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // we don't synchronize on the iterator, assuming that an iterator is only used in one thread. 73451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // we do synchronize access to the AttributedString however, since it's more likely to be shared between threads. 73551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 73651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // start and end index for our iteration 73751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private int beginIndex; 73851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private int endIndex; 73951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 74051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // attributes that our client is interested in 74151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private Attribute[] relevantAttributes; 74251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 74351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // the current index for our iteration 74451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // invariant: beginIndex <= currentIndex <= endIndex 74551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private int currentIndex; 74651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 74751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // information about the run that includes currentIndex 74851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private int currentRunIndex; 74951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private int currentRunStart; 75051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private int currentRunLimit; 75151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 75251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // constructor 75351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski AttributedStringIterator(Attribute[] attributes, int beginIndex, int endIndex) { 75451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 75551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (beginIndex < 0 || beginIndex > endIndex || endIndex > length()) { 75651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski throw new IllegalArgumentException("Invalid substring range"); 75751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 75851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 75951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski this.beginIndex = beginIndex; 76051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski this.endIndex = endIndex; 76151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski this.currentIndex = beginIndex; 76251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski updateRunInfo(); 76351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (attributes != null) { 76451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski relevantAttributes = (Attribute[]) attributes.clone(); 76551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 76651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 76751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 76851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // Object methods. See documentation in that class. 76951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 77051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public boolean equals(Object obj) { 77151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (this == obj) { 77251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return true; 77351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 77451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (!(obj instanceof AttributedStringIterator)) { 77551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return false; 77651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 77751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 77851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski AttributedStringIterator that = (AttributedStringIterator) obj; 77951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 78051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (AttributedString.this != that.getString()) 78151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return false; 78251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (currentIndex != that.currentIndex || beginIndex != that.beginIndex || endIndex != that.endIndex) 78351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return false; 78451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return true; 78551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 78651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 78751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public int hashCode() { 78851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return text.hashCode() ^ currentIndex ^ beginIndex ^ endIndex; 78951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 79051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 79151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public Object clone() { 79251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski try { 79351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski AttributedStringIterator other = (AttributedStringIterator) super.clone(); 79451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return other; 79551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 79651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski catch (CloneNotSupportedException e) { 79751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski throw new InternalError(); 79851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 79951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 80051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 80151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // CharacterIterator methods. See documentation in that interface. 80251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 80351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public char first() { 80451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return internalSetIndex(beginIndex); 80551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 80651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 80751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public char last() { 80851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (endIndex == beginIndex) { 80951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return internalSetIndex(endIndex); 81051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } else { 81151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return internalSetIndex(endIndex - 1); 81251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 81351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 81451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 81551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public char current() { 81651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (currentIndex == endIndex) { 81751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return DONE; 81851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } else { 81951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return charAt(currentIndex); 82051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 82151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 82251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 82351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public char next() { 82451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (currentIndex < endIndex) { 82551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return internalSetIndex(currentIndex + 1); 82651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 82751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski else { 82851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return DONE; 82951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 83051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 83151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 83251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public char previous() { 83351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (currentIndex > beginIndex) { 83451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return internalSetIndex(currentIndex - 1); 83551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 83651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski else { 83751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return DONE; 83851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 83951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 84051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 84151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public char setIndex(int position) { 84251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (position < beginIndex || position > endIndex) 84351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski throw new IllegalArgumentException("Invalid index"); 84451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return internalSetIndex(position); 84551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 84651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 84751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public int getBeginIndex() { 84851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return beginIndex; 84951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 85051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 85151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public int getEndIndex() { 85251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return endIndex; 85351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 85451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 85551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public int getIndex() { 85651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return currentIndex; 85751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 85851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 85951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // AttributedCharacterIterator methods. See documentation in that interface. 86051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 86151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public int getRunStart() { 86251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return currentRunStart; 86351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 86451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 86551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public int getRunStart(Attribute attribute) { 86651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (currentRunStart == beginIndex || currentRunIndex == -1) { 86751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return currentRunStart; 86851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } else { 86951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Object value = getAttribute(attribute); 87051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int runStart = currentRunStart; 87151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int runIndex = currentRunIndex; 87251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski while (runStart > beginIndex && 87351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski valuesMatch(value, AttributedString.this.getAttribute(attribute, runIndex - 1))) { 87451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runIndex--; 87551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runStart = runStarts[runIndex]; 87651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 87751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (runStart < beginIndex) { 87851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runStart = beginIndex; 87951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 88051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return runStart; 88151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 88251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 88351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 88451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public int getRunStart(Set<? extends Attribute> attributes) { 88551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (currentRunStart == beginIndex || currentRunIndex == -1) { 88651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return currentRunStart; 88751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } else { 88851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int runStart = currentRunStart; 88951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int runIndex = currentRunIndex; 89051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski while (runStart > beginIndex && 89151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski AttributedString.this.attributeValuesMatch(attributes, currentRunIndex, runIndex - 1)) { 89251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runIndex--; 89351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runStart = runStarts[runIndex]; 89451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 89551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (runStart < beginIndex) { 89651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runStart = beginIndex; 89751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 89851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return runStart; 89951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 90051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 90151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 90251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public int getRunLimit() { 90351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return currentRunLimit; 90451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 90551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 90651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public int getRunLimit(Attribute attribute) { 90751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (currentRunLimit == endIndex || currentRunIndex == -1) { 90851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return currentRunLimit; 90951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } else { 91051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Object value = getAttribute(attribute); 91151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int runLimit = currentRunLimit; 91251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int runIndex = currentRunIndex; 91351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski while (runLimit < endIndex && 91451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski valuesMatch(value, AttributedString.this.getAttribute(attribute, runIndex + 1))) { 91551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runIndex++; 91651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runLimit = runIndex < runCount - 1 ? runStarts[runIndex + 1] : endIndex; 91751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 91851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (runLimit > endIndex) { 91951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runLimit = endIndex; 92051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 92151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return runLimit; 92251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 92351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 92451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 92551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public int getRunLimit(Set<? extends Attribute> attributes) { 92651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (currentRunLimit == endIndex || currentRunIndex == -1) { 92751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return currentRunLimit; 92851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } else { 92951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int runLimit = currentRunLimit; 93051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int runIndex = currentRunIndex; 93151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski while (runLimit < endIndex && 93251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski AttributedString.this.attributeValuesMatch(attributes, currentRunIndex, runIndex + 1)) { 93351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runIndex++; 93451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runLimit = runIndex < runCount - 1 ? runStarts[runIndex + 1] : endIndex; 93551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 93651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (runLimit > endIndex) { 93751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runLimit = endIndex; 93851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 93951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return runLimit; 94051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 94151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 94251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 94351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public Map<Attribute,Object> getAttributes() { 94451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (runAttributes == null || currentRunIndex == -1 || runAttributes[currentRunIndex] == null) { 94551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // ??? would be nice to return null, but current spec doesn't allow it 94651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // returning Hashtable saves AttributeMap from dealing with emptiness 94751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return new Hashtable(); 94851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 94951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return new AttributeMap(currentRunIndex, beginIndex, endIndex); 95051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 95151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 95251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public Set<Attribute> getAllAttributeKeys() { 95351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // ??? This should screen out attribute keys that aren't relevant to the client 95451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (runAttributes == null) { 95551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // ??? would be nice to return null, but current spec doesn't allow it 95651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // returning HashSet saves us from dealing with emptiness 95751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return new HashSet(); 95851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 95951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski synchronized (AttributedString.this) { 96051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // ??? should try to create this only once, then update if necessary, 96151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // and give callers read-only view 96251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Set keys = new HashSet(); 96351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int i = 0; 96451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski while (i < runCount) { 96551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (runStarts[i] < endIndex && (i == runCount - 1 || runStarts[i + 1] > beginIndex)) { 96651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Vector currentRunAttributes = runAttributes[i]; 96751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (currentRunAttributes != null) { 96851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int j = currentRunAttributes.size(); 96951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski while (j-- > 0) { 97051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski keys.add(currentRunAttributes.get(j)); 97151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 97251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 97351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 97451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski i++; 97551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 97651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return keys; 97751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 97851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 97951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 98051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public Object getAttribute(Attribute attribute) { 98151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int runIndex = currentRunIndex; 98251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (runIndex < 0) { 98351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return null; 98451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 98551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return AttributedString.this.getAttributeCheckRange(attribute, runIndex, beginIndex, endIndex); 98651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 98751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 98851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // internally used methods 98951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 99051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private AttributedString getString() { 99151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return AttributedString.this; 99251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 99351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 99451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // set the current index, update information about the current run if necessary, 99551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // return the character at the current index 99651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private char internalSetIndex(int position) { 99751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski currentIndex = position; 99851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (position < currentRunStart || position >= currentRunLimit) { 99951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski updateRunInfo(); 100051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 100151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (currentIndex == endIndex) { 100251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return DONE; 100351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } else { 100451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return charAt(position); 100551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 100651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 100751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 100851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // update the information about the current run 100951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private void updateRunInfo() { 101051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (currentIndex == endIndex) { 101151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski currentRunStart = currentRunLimit = endIndex; 101251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski currentRunIndex = -1; 101351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } else { 101451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski synchronized (AttributedString.this) { 101551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int runIndex = -1; 101651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski while (runIndex < runCount - 1 && runStarts[runIndex + 1] <= currentIndex) 101751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runIndex++; 101851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski currentRunIndex = runIndex; 101951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (runIndex >= 0) { 102051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski currentRunStart = runStarts[runIndex]; 102151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (currentRunStart < beginIndex) 102251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski currentRunStart = beginIndex; 102351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 102451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski else { 102551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski currentRunStart = beginIndex; 102651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 102751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (runIndex < runCount - 1) { 102851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski currentRunLimit = runStarts[runIndex + 1]; 102951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (currentRunLimit > endIndex) 103051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski currentRunLimit = endIndex; 103151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 103251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski else { 103351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski currentRunLimit = endIndex; 103451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 103551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 103651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 103751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 103851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 103951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 104051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 104151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // the map class associated with this string class, giving access to the attributes of one run 104251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 104351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski final private class AttributeMap extends AbstractMap<Attribute,Object> { 104451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 104551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int runIndex; 104651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int beginIndex; 104751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int endIndex; 104851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 104951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski AttributeMap(int runIndex, int beginIndex, int endIndex) { 105051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski this.runIndex = runIndex; 105151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski this.beginIndex = beginIndex; 105251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski this.endIndex = endIndex; 105351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 105451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 105551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public Set entrySet() { 105651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski HashSet set = new HashSet(); 105751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski synchronized (AttributedString.this) { 105851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int size = runAttributes[runIndex].size(); 105951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski for (int i = 0; i < size; i++) { 106051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Attribute key = (Attribute) runAttributes[runIndex].get(i); 106151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Object value = runAttributeValues[runIndex].get(i); 106251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (value instanceof Annotation) { 106351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski value = AttributedString.this.getAttributeCheckRange(key, 106451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski runIndex, beginIndex, endIndex); 106551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (value == null) { 106651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski continue; 106751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 106851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 106951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski Map.Entry entry = new AttributeEntry(key, value); 107051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski set.add(entry); 107151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 107251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 107351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return set; 107451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 107551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 107651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public Object get(Object key) { 107751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return AttributedString.this.getAttributeCheckRange((Attribute) key, runIndex, beginIndex, endIndex); 107851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 107951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 108051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski} 108151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 108251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiclass AttributeEntry implements Map.Entry { 108351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 108451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private Attribute key; 108551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private Object value; 108651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 108751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski AttributeEntry(Attribute key, Object value) { 108851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski this.key = key; 108951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski this.value = value; 109051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 109151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 109251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public boolean equals(Object o) { 109351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (!(o instanceof AttributeEntry)) { 109451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return false; 109551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 109651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski AttributeEntry other = (AttributeEntry) o; 109751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return other.key.equals(key) && 109851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski (value == null ? other.value == null : other.value.equals(value)); 109951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 110051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 110151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public Object getKey() { 110251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return key; 110351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 110451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 110551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public Object getValue() { 110651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return value; 110751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 110851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 110951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public Object setValue(Object newValue) { 111051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski throw new UnsupportedOperationException(); 111151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 111251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 111351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public int hashCode() { 111451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return key.hashCode() ^ (value==null ? 0 : value.hashCode()); 111551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 111651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 111751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public String toString() { 111851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return key.toString()+"="+value.toString(); 111951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 112051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski} 1121