/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is NetBeans. The Initial Developer of the Original
* Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun
* Microsystems, Inc. All Rights Reserved.
*/
package org.openide.text;
import java.awt.Font;
import java.awt.Color;
import java.awt.font.TextAttribute;
import java.text.AttributedCharacterIterator;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.Collections;
import java.util.HashSet;
/** The class is a support for all classes that implement PrintCookie.
* Allows creating of attributed texts.
*
* @author Ales Novak
*/
public class AttributedCharacters extends Object {
/** Characters to iterate. */
protected char[] chars;
/** Font for each character. */
protected Font[] fonts;
/** Color for each character. */
protected Color[] colors;
/** Start indices of continuous blocks of text with the same font. */
protected int[] runStart;
/** Limit indices of continous ... */
protected int[] runLimit;
/** Current. */
protected int current;
public AttributedCharacters() {
chars = new char[10];
fonts = new Font[10];
colors = new Color[10];
runStart = new int[10];
runLimit = new int[10];
current = -1;
}
/** Append a character with specified font.
* @param c character to append
* @param f a Font
* @param color a Color
*/
public void append(char c, Font f, Color color) {
if (f == null) return;
if (++current == chars.length) {
char[] ctmp = new char[2 * chars.length];
Font[] ftmp = new Font[2 * chars.length];
Color[] cotmp = new Color[2 * chars.length];
int[] rstmp = new int[2 * chars.length];
int[] rltmp = new int[2 * chars.length];
System.arraycopy(chars, 0, ctmp, 0, chars.length);
System.arraycopy(fonts, 0, ftmp, 0, chars.length);
System.arraycopy(colors, 0, cotmp, 0, chars.length);
System.arraycopy(runStart, 0, rstmp, 0, chars.length);
System.arraycopy(runLimit, 0, rltmp, 0, chars.length);
chars = ctmp;
fonts = ftmp;
colors = cotmp;
runStart = rstmp;
runLimit = rltmp;
}
chars[current] = c;
fonts[current] = f;
colors[current] = color;
if (current != 0) {
int prev = current - 1;
if (fonts[prev].equals(f) && colors[prev].equals(color)) {
runLimit[runStart[current] = runStart[prev]] = current;
} else {
runLimit[current] = current;
runStart[current] = current;
}
}
}
/** Append a character array with a font.
* @param a characters to append
* @param f a font to use
* @param color a color to use
*/
public void append(char[] a, Font f, Color color) {
if (a == null || a.length == 0 || f == null || color == null) {
return;
}
// increase buffers
if (++current + a.length >= chars.length) {
int size = Math.max(current + a.length, 2 * chars.length);
char[] ctmp = new char[size];
Font[] ftmp = new Font[size];
Color[] cotmp = new Color[size];
int[] rstmp = new int[size];
int[] rltmp = new int[size];
System.arraycopy(chars, 0, ctmp, 0, chars.length);
System.arraycopy(fonts, 0, ftmp, 0, fonts.length);
System.arraycopy(colors, 0, cotmp, 0, chars.length);
System.arraycopy(runStart, 0, rstmp, 0, chars.length);
System.arraycopy(runLimit, 0, rltmp, 0, chars.length);
chars = ctmp;
fonts = ftmp;
colors = cotmp;
runStart = rstmp;
runLimit = rltmp;
}
// fill buffers
System.arraycopy(a, 0, chars, current, a.length);
for (int i = 0; i < a.length; i++) {
fonts[i + current] = f;
colors[i + current] = color;
}
// update last member to be the runLimit for the first one in the block
int prev = current - 1;
int pseudo = current + a.length - 1;
if (prev < 0) { // start?
runLimit[0] = pseudo;
} else {
int replace;
if (fonts[prev].equals(f) && colors[prev].equals(color)) { // increase old block
runLimit[replace = runStart[pseudo] = runStart[prev]] = pseudo;
} else { // new block
runLimit[current] = pseudo;
runStart[current] = current;
runStart[pseudo] = current;
replace = current;
}
// init items in the block - update runStart
for (int i = current + 1; i < pseudo; i++) {
runStart[i] = replace;
}
}
current = pseudo;
}
/** Produce an appropriate character iterator.
* @return an iterator
*/
public AttributedCharacterIterator iterator() {
int size = current + 1;
char[] cs = new char[size];
Font[] fs = new Font[size];
Color[] colos = new Color[size];
int[] rstmp = new int[size];
int[] rltmp = new int[size];
System.arraycopy(runStart, 0, rstmp, 0, size);
System.arraycopy(runLimit, 0, rltmp, 0, size);
System.arraycopy(chars, 0, cs, 0, size);
System.arraycopy(fonts, 0, fs, 0, size);
System.arraycopy(colors, 0, colos, 0, size);
AttributedCharacterIterator ret = new AttributedCharacterIteratorImpl(cs, fs, colos, rstmp, rltmp);
return ret;
}
/** Implementation of AttributedCharacterIterator interface. */
public static class AttributedCharacterIteratorImpl
implements AttributedCharacterIterator {
/** Current position. */
protected int current;
/** Characters to iterate. */
protected char[] chars;
/** Font for each character. */
protected Font[] fonts;
/** Color for each character. */
protected Color[] colors;
/** Start indices of continuous blocks of text with the same font. */
protected int[] runStart;
/** Limit indices of continous ... */
protected int[] runLimit;
/** Singleton. */
protected Set singleton;
public AttributedCharacterIteratorImpl(char[] chars,
Font[] fonts,
Color[] colors,
int[] rs,
int[] rl) {
this.chars = chars;
this.fonts = fonts;
this.colors = colors;
runStart = rs;
runLimit = rl;
}
// first implement CharacterIterator
/*
* Clones the object.
* @return a clone
*/
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
// impossible to catch it
return null;
}
}
/*
* @return current char
*/
public char current() {
if (current >= chars.length) return DONE;
return chars[current];
}
/*
* @return first char
*/
public char first() {
current = 0;
if (current >= chars.length) return DONE;
return chars[current];
}
/*
* @return begin index
*/
public int getBeginIndex() {
return 0;
}
/*
* @return end index
*/
public int getEndIndex() {
return chars.length;
}
/*
* @return current index
*/
public int getIndex() {
return current;
}
/*
* @return character at last index
*/
public char last() {
int end = getEndIndex();
if (end == 0) {
return DONE;
}
return chars[current = end - 1];
}
/*
* @return next char
*/
public char next() {
if (current >= getEndIndex() - 1) {
return DONE;
}
return chars[++current];
}
/*
* @return previous char
*/
public char previous() {
if (current == 0) {
return DONE;
}
return chars[--current];
}
/*
* @param i new index
* @return char at that position
*/
public char setIndex(int i) {
if (i < 0) throw new IllegalArgumentException();
if (i == getEndIndex()) {
current = getEndIndex();
return DONE;
}
return chars[current = i];
}
// attributes
/*
* @return a Set with TextAttribute.FONT
*/
public Set getAllAttributeKeys() {
if (singleton == null) {
HashSet l = new HashSet(4);
l.add(TextAttribute.FONT);
l.add(TextAttribute.FOREGROUND);
singleton = Collections.unmodifiableSet(l);
}
return singleton;
}
/*
* @param att an Attribute
* @return a value for this attribute
*/
public Object getAttribute(AttributedCharacterIterator.Attribute att) {
if (att == TextAttribute.FONT) {
return fonts[getIndex()];
} else if (att == TextAttribute.FOREGROUND) {
return colors[getIndex()];
} else {
return null;
}
}
/*
* @return map with all attributes for current char
*/
public Map getAttributes() {
Map m = new HashMap(1);
m.put(TextAttribute.FONT, fonts[getIndex()]);
m.put(TextAttribute.FOREGROUND, colors[getIndex()]);
return m;
}
/*
* @return
*/
public int getRunLimit() {
return runLimit[runStart[getIndex()]] + 1;
}
/*
* @param att an Attribute
*/
public int getRunLimit(AttributedCharacterIterator.Attribute att) {
if ((att != TextAttribute.FONT) &&
(att != TextAttribute.FOREGROUND)) {
return getEndIndex(); // undefined attribute
}
return getRunLimit();
}
/*
* @param attributes a Set of attributes
*/
public int getRunLimit(Set attributes) {
if (attributes.contains(TextAttribute.FONT) ||
attributes.contains(TextAttribute.FOREGROUND)
) {
return getRunLimit();
} else {
return getEndIndex();
}
}
/*
* @return run start for current char
*/
public int getRunStart() {
return runStart[getIndex()];
}
/*
* @param att
*/
public int getRunStart(AttributedCharacterIterator.Attribute att) {
if ((att != TextAttribute.FONT) &&
att != TextAttribute.FOREGROUND) {
return 0; // undefined attribute
}
return getRunStart();
}
/*
* @param attributes a Set
*/
public int getRunStart(Set attributes) {
if ((attributes.contains(TextAttribute.FONT)) ||
attributes.contains(TextAttribute.FOREGROUND)
) {
return getRunStart();
} else {
return 0;
}
}
}
}