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