/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* An AttributedString holds text and related attribute information. It
* may be used as the actual data storage in some cases where a text
* reader wants to access attributed text through the AttributedCharacterIterator
* interface.
*
* <p>
* attributes on a given character can have the same key.
*
* <p>The values for an attribute are immutable, or must not be mutated
* by clients or storage. They are always passed by reference, and not
* cloned.
*
* @see AttributedCharacterIterator
* @see Annotation
* @since 1.2
*/
public class AttributedString {
// since there are no vectors of int, we have to use arrays.
// We allocate them in chunks of 10 elements so we don't have to allocate all the time.
// field holding the text
// fields holding run attribute information
// run attributes are organized by run
/**
* Constructs an AttributedString instance with the given
* AttributedCharacterIterators.
*
* @param iterators AttributedCharacterIterators to construct
* AttributedString from.
* @throws NullPointerException if iterators is null
*/
throw new NullPointerException("Iterators must not be null");
}
text = "";
}
else {
// Build the String contents
}
// Determine the runs, creating a new run when the attributes
// differ.
int offset = 0;
}
}
}
}
}
}
/**
* Constructs an AttributedString instance with the given text.
* @param text The text for this attributed string.
* @exception NullPointerException if <code>text</code> is null.
*/
throw new NullPointerException();
}
}
/**
* Constructs an AttributedString instance with the given text and attributes.
* @param text The text for this attributed string.
* @param attributes The attributes that apply to the entire string.
* @exception NullPointerException if <code>text</code> or
* <code>attributes</code> is null.
* @exception IllegalArgumentException if the text has length 0
* and the attributes parameter is not an empty Map (attributes
* cannot be applied to a 0-length range).
*/
{
throw new NullPointerException();
}
if (attributes.isEmpty())
return;
throw new IllegalArgumentException("Can't add attribute to 0-length text");
}
if (attributeCount > 0) {
}
}
}
/**
* Constructs an AttributedString instance with the given attributed
* text represented by AttributedCharacterIterator.
* @param text The text for this attributed string.
* @exception NullPointerException if <code>text</code> is null.
*/
// If performance is critical, this constructor should be
// implemented here rather than invoking the constructor for a
// subrange. We can avoid some range checking in the loops.
}
/**
* Constructs an AttributedString instance with the subrange of
* the given attributed text represented by
* AttributedCharacterIterator. If the given range produces an
* empty text, all attributes will be discarded. Note that any
* attributes wrapped by an Annotation object are discarded for a
* subrange of the original attribute range.
*
* @param text The text for this attributed string.
* @param beginIndex Index of the first character of the range.
* @param endIndex Index of the character following the last character
* of the range.
* @exception NullPointerException if <code>text</code> is null.
* @exception IllegalArgumentException if the subrange given by
* beginIndex and endIndex is out of the text range.
* @see java.text.Annotation
*/
int beginIndex,
int endIndex) {
}
/**
* Constructs an AttributedString instance with the subrange of
* the given attributed text represented by
* AttributedCharacterIterator. Only attributes that match the
* given attributes will be incorporated into the instance. If the
* given range produces an empty text, all attributes will be
* discarded. Note that any attributes wrapped by an Annotation
* object are discarded for a subrange of the original attribute
* range.
*
* @param text The text for this attributed string.
* @param beginIndex Index of the first character of the range.
* @param endIndex Index of the character following the last character
* of the range.
* @param attributes Specifies attributes to be extracted
* from the text. If null is specified, all available attributes will
* be used.
* @exception NullPointerException if <code>text</code> is null.
* @exception IllegalArgumentException if the subrange given by
* beginIndex and endIndex is out of the text range.
* @see java.text.Annotation
*/
int beginIndex,
int endIndex,
Attribute[] attributes) {
throw new NullPointerException();
}
// Validate the given subrange
throw new IllegalArgumentException("Invalid substring range");
// Copy the given string
textBuffer.append(c);
if (beginIndex == endIndex)
return;
// Select attribute keys to be taken care of
if (attributes == null) {
} else {
}
return;
// Get and set attribute runs for each attribute name. Need to
// scan from the top of the text so that we can discard any
// Annotation that is no longer applied to a subset text segment.
if (value instanceof Annotation) {
} else {
break;
}
} else {
// if the run is beyond the given (subset) range, we
// don't need to process further.
break;
if (limit > beginIndex) {
// attribute is applied to any subrange
if (start < beginIndex)
start = beginIndex;
}
}
}
}
}
}
}
/**
* Adds an attribute to the entire string.
* @param attribute the attribute key
* @param value the value of the attribute; may be null
* @exception NullPointerException if <code>attribute</code> is null.
* @exception IllegalArgumentException if the AttributedString has length 0
* (attributes cannot be applied to a 0-length range).
*/
throw new NullPointerException();
}
if (len == 0) {
throw new IllegalArgumentException("Can't add attribute to 0-length text");
}
}
/**
* Adds an attribute to a subrange of the string.
* @param attribute the attribute key
* @param value The value of the attribute. May be null.
* @param beginIndex Index of the first character of the range.
* @param endIndex Index of the character following the last character of the range.
* @exception NullPointerException if <code>attribute</code> is null.
* @exception IllegalArgumentException if beginIndex is less then 0, endIndex is
* greater than the length of the string, or beginIndex and endIndex together don't
* define a non-empty subrange of the string.
*/
int beginIndex, int endIndex) {
throw new NullPointerException();
}
throw new IllegalArgumentException("Invalid substring range");
}
}
/**
* Adds a set of attributes to a subrange of the string.
* @param attributes The attributes to be added to the string.
* @param beginIndex Index of the first character of the range.
* @param endIndex Index of the character following the last
* character of the range.
* @exception NullPointerException if <code>attributes</code> is null.
* @exception IllegalArgumentException if beginIndex is less then
* 0, endIndex is greater than the length of the string, or
* beginIndex and endIndex together don't define a non-empty
* subrange of the string and the attributes parameter is not an
* empty Map.
*/
int beginIndex, int endIndex)
{
if (attributes == null) {
throw new NullPointerException();
}
throw new IllegalArgumentException("Invalid substring range");
}
if (beginIndex == endIndex) {
if (attributes.isEmpty())
return;
throw new IllegalArgumentException("Can't add attribute to 0-length text");
}
// make sure we have run attribute data vectors
if (runCount == 0) {
}
// break up runs if necessary
}
}
int beginIndex, int endIndex) {
// make sure we have run attribute data vectors
if (runCount == 0) {
}
// break up runs if necessary
}
private final void createRunAttributeDataVectors() {
// use temporary variables so things remain consistent in case of an exception
int newRunStarts[] = new int[ARRAY_SIZE_INCREMENT];
}
// ensure there's a run break at offset, return the index of the run
return ensureRunBreak(offset, true);
}
/**
* Ensures there is a run break at offset, returning the index of
* the run. If this results in splitting a run, two things can happen:
* <ul>
* <li>If copyAttrs is true, the attributes from the existing run
* will be placed in both of the newly created runs.
* <li>If copyAttrs is false, the attributes from the existing run
* will NOT be copied to the run to the right (>= offset) of the break,
* but will exist on the run to the left (< offset).
* </ul>
*/
return runCount;
}
// search for the run index where this offset should be
int runIndex = 0;
runIndex++;
}
// if the offset is at a run start already, we're done
return runIndex;
}
// we'll have to break up a run
// first, make sure we have enough space in our arrays
if (runCount == runArraySize) {
int newRunStarts[] = new int[newArraySize];
for (int i = 0; i < runArraySize; i++) {
newRunStarts[i] = runStarts[i];
newRunAttributes[i] = runAttributes[i];
newRunAttributeValues[i] = runAttributeValues[i];
}
}
// make copies of the attribute information of the old run that the new one used to be part of
// use temporary variables so things remain consistent in case of an exception
if (copyAttrs) {
if (oldRunAttributes != null) {
}
if (oldRunAttributeValues != null) {
}
}
// now actually break up the run
runCount++;
}
return runIndex;
}
int beginRunIndex, int endRunIndex) {
for (int i = beginRunIndex; i < endRunIndex; i++) {
if (runAttributes[i] == null) {
} else {
// check whether we have an entry already
}
if (keyValueIndex == -1) {
// create new entry
try {
}
catch (Exception e) {
}
} else {
// update existing entry
}
}
}
/**
* Creates an AttributedCharacterIterator instance that provides access to the entire contents of
* this string.
*
* @return An iterator providing access to the text and its attributes.
*/
}
/**
* Creates an AttributedCharacterIterator instance that provides access to
* selected contents of this string.
* Information about attributes not listed in attributes that the
* implementor may have need not be made accessible through the iterator.
* If the list is null, all available attribute information should be made
* accessible.
*
* @param attributes a list of attributes that the client is interested in
* @return an iterator providing access to the entire text and its selected attributes
*/
}
/**
* Creates an AttributedCharacterIterator instance that provides access to
* selected contents of this string.
* Information about attributes not listed in attributes that the
* implementor may have need not be made accessible through the iterator.
* If the list is null, all available attribute information should be made
* accessible.
*
* @param attributes a list of attributes that the client is interested in
* @param beginIndex the index of the first character
* @param endIndex the index of the character following the last character
* @return an iterator providing access to the text and its attributes
* @exception IllegalArgumentException if beginIndex is less then 0,
* endIndex is greater than the length of the string, or beginIndex is
* greater than endIndex.
*/
public AttributedCharacterIterator getIterator(Attribute[] attributes, int beginIndex, int endIndex) {
}
// all (with the exception of length) reading operations are private,
// since AttributedString instances are accessed through iterators.
// length is package private so that CharacterIteratorFieldDelegate can
// access it without creating an AttributedCharacterIterator.
int length() {
}
}
if (currentRunAttributes == null) {
return null;
}
if (attributeIndex != -1) {
}
else {
return null;
}
}
// gets an attribute value, but returns an annotation only if it's range does not extend outside the range beginIndex..endIndex
private Object getAttributeCheckRange(Attribute attribute, int runIndex, int beginIndex, int endIndex) {
if (value instanceof Annotation) {
// need to check whether the annotation's range extends outside the iterator's range
if (beginIndex > 0) {
while (runStart >= beginIndex &&
currIndex--;
}
if (runStart < beginIndex) {
// annotation's range starts before iterator's range
return null;
}
}
int textLength = length();
if (endIndex < textLength) {
currIndex++;
}
// annotation's range ends after iterator's range
return null;
}
}
// annotation's range is subrange of iterator's range,
// so we can return the value
}
return value;
}
// returns whether all specified attributes have equal values in the runs with the given indices
return false;
}
}
return true;
}
// returns whether the two objects are either both null or equal
} else {
}
}
/**
* Appends the contents of the CharacterIterator iterator into the
* StringBuffer buf.
*/
}
}
/**
* Sets the attributes for the range from offset to the next run break
* (typically the end of the text) to the ones specified in attrs.
* This is only meant to be called from the constructor!
*/
if (runCount == 0) {
}
int size;
}
}
}
/**
* Returns true if the attributes specified in last and attrs differ.
*/
}
}
// the iterator class associated with this string class
// note on synchronization:
// we don't synchronize on the iterator, assuming that an iterator is only used in one thread.
// we do synchronize access to the AttributedString however, since it's more likely to be shared between threads.
// start and end index for our iteration
private int beginIndex;
private int endIndex;
// attributes that our client is interested in
// the current index for our iteration
// invariant: beginIndex <= currentIndex <= endIndex
private int currentIndex;
// information about the run that includes currentIndex
private int currentRunIndex;
private int currentRunStart;
private int currentRunLimit;
// constructor
throw new IllegalArgumentException("Invalid substring range");
}
this.beginIndex = beginIndex;
this.currentIndex = beginIndex;
if (attributes != null) {
}
}
// Object methods. See documentation in that class.
if (this == obj) {
return true;
}
if (!(obj instanceof AttributedStringIterator)) {
return false;
}
return false;
if (currentIndex != that.currentIndex || beginIndex != that.beginIndex || endIndex != that.endIndex)
return false;
return true;
}
public int hashCode() {
}
try {
return other;
}
catch (CloneNotSupportedException e) {
throw new InternalError();
}
}
// CharacterIterator methods. See documentation in that interface.
public char first() {
return internalSetIndex(beginIndex);
}
public char last() {
if (endIndex == beginIndex) {
return internalSetIndex(endIndex);
} else {
}
}
public char current() {
if (currentIndex == endIndex) {
return DONE;
} else {
return charAt(currentIndex);
}
}
public char next() {
if (currentIndex < endIndex) {
}
else {
return DONE;
}
}
public char previous() {
if (currentIndex > beginIndex) {
}
else {
return DONE;
}
}
throw new IllegalArgumentException("Invalid index");
return internalSetIndex(position);
}
public int getBeginIndex() {
return beginIndex;
}
public int getEndIndex() {
return endIndex;
}
public int getIndex() {
return currentIndex;
}
// AttributedCharacterIterator methods. See documentation in that interface.
public int getRunStart() {
return currentRunStart;
}
return currentRunStart;
} else {
int runStart = currentRunStart;
int runIndex = currentRunIndex;
while (runStart > beginIndex &&
runIndex--;
}
if (runStart < beginIndex) {
}
return runStart;
}
}
return currentRunStart;
} else {
int runStart = currentRunStart;
int runIndex = currentRunIndex;
while (runStart > beginIndex &&
runIndex--;
}
if (runStart < beginIndex) {
}
return runStart;
}
}
public int getRunLimit() {
return currentRunLimit;
}
return currentRunLimit;
} else {
int runLimit = currentRunLimit;
int runIndex = currentRunIndex;
runIndex++;
}
}
return runLimit;
}
}
return currentRunLimit;
} else {
int runLimit = currentRunLimit;
int runIndex = currentRunIndex;
runIndex++;
}
}
return runLimit;
}
}
// ??? would be nice to return null, but current spec doesn't allow it
// returning Hashtable saves AttributeMap from dealing with emptiness
return new Hashtable();
}
}
// ??? This should screen out attribute keys that aren't relevant to the client
if (runAttributes == null) {
// ??? would be nice to return null, but current spec doesn't allow it
// returning HashSet saves us from dealing with emptiness
return new HashSet();
}
synchronized (AttributedString.this) {
// ??? should try to create this only once, then update if necessary,
// and give callers read-only view
int i = 0;
while (i < runCount) {
if (currentRunAttributes != null) {
int j = currentRunAttributes.size();
while (j-- > 0) {
}
}
}
i++;
}
return keys;
}
}
int runIndex = currentRunIndex;
if (runIndex < 0) {
return null;
}
}
// internally used methods
return AttributedString.this;
}
// set the current index, update information about the current run if necessary,
// return the character at the current index
}
if (currentIndex == endIndex) {
return DONE;
} else {
}
}
// update the information about the current run
private void updateRunInfo() {
if (currentIndex == endIndex) {
currentRunIndex = -1;
} else {
synchronized (AttributedString.this) {
int runIndex = -1;
runIndex++;
if (runIndex >= 0) {
if (currentRunStart < beginIndex)
}
else {
}
if (currentRunLimit > endIndex)
}
else {
}
}
}
}
}
// the map class associated with this string class, giving access to the attributes of one run
int runIndex;
int beginIndex;
int endIndex;
this.beginIndex = beginIndex;
}
synchronized (AttributedString.this) {
for (int i = 0; i < size; i++) {
if (value instanceof Annotation) {
continue;
}
}
}
}
return set;
}
return AttributedString.this.getAttributeCheckRange((Attribute) key, runIndex, beginIndex, endIndex);
}
}
}
}
if (!(o instanceof AttributeEntry)) {
return false;
}
}
return key;
}
return value;
}
throw new UnsupportedOperationException();
}
public int hashCode() {
}
}
}