下面列出了java.text.AttributedCharacterIterator#next ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
/**
* Draws a string of attributed characters at {@code (x, y)}.
*
* @param iterator an iterator over the characters ({@code null} not
* permitted).
* @param x the x-coordinate.
* @param y the y-coordinate.
*/
@Override
public void drawString(AttributedCharacterIterator iterator, float x,
float y) {
Set<AttributedCharacterIterator.Attribute>
s = iterator.getAllAttributeKeys();
if (!s.isEmpty()) {
TextLayout layout = new TextLayout(iterator,
getFontRenderContext());
layout.draw(this, x, y);
} else {
StringBuilder strb = new StringBuilder();
iterator.first();
for (int i = iterator.getBeginIndex(); i < iterator.getEndIndex();
i++) {
strb.append(iterator.current());
iterator.next();
}
drawString(strb.toString(), x, y);
}
}
private static final void checkIteratorText(AttributedCharacterIterator iterator, String expectedText) throws Exception {
if (iterator.getEndIndex() - iterator.getBeginIndex() != expectedText.length()) {
throwException(iterator, "text length doesn't match between original text and iterator");
}
char c = iterator.first();
for (int i = 0; i < expectedText.length(); i++) {
if (c != expectedText.charAt(i)) {
throwException(iterator, "text content doesn't match between original text and iterator");
}
c = iterator.next();
}
if (c != CharacterIterator.DONE) {
throwException(iterator, "iterator text doesn't end with DONE");
}
}
/**
* Draws a string of attributed characters at {@code (x, y)}.
*
* @param iterator an iterator over the characters ({@code null} not
* permitted).
* @param x the x-coordinate.
* @param y the y-coordinate.
*/
@Override
public void drawString(AttributedCharacterIterator iterator, float x,
float y) {
Set<AttributedCharacterIterator.Attribute>
s = iterator.getAllAttributeKeys();
if (!s.isEmpty()) {
TextLayout layout = new TextLayout(iterator,
getFontRenderContext());
layout.draw(this, x, y);
} else {
StringBuilder strb = new StringBuilder();
iterator.first();
for (int i = iterator.getBeginIndex(); i < iterator.getEndIndex();
i++) {
strb.append(iterator.current());
iterator.next();
}
drawString(strb.toString(), x, y);
}
}
private static final void checkIteratorText(AttributedCharacterIterator iterator, String expectedText) throws Exception {
if (iterator.getEndIndex() - iterator.getBeginIndex() != expectedText.length()) {
throwException(iterator, "text length doesn't match between original text and iterator");
}
char c = iterator.first();
for (int i = 0; i < expectedText.length(); i++) {
if (c != expectedText.charAt(i)) {
throwException(iterator, "text content doesn't match between original text and iterator");
}
c = iterator.next();
}
if (c != CharacterIterator.DONE) {
throwException(iterator, "iterator text doesn't end with DONE");
}
}
/**
* Draws a string of attributed characters at {@code (x, y)}.
*
* @param iterator an iterator over the characters ({@code null} not
* permitted).
* @param x the x-coordinate.
* @param y the y-coordinate.
*/
@Override
public void drawString(AttributedCharacterIterator iterator, float x,
float y) {
Set<Attribute> s = iterator.getAllAttributeKeys();
if (!s.isEmpty()) {
TextLayout layout = new TextLayout(iterator,
getFontRenderContext());
layout.draw(this, x, y);
} else {
StringBuilder strb = new StringBuilder();
iterator.first();
for (int i = iterator.getBeginIndex(); i < iterator.getEndIndex();
i++) {
strb.append(iterator.current());
iterator.next();
}
drawString(strb.toString(), x, y);
}
}
private void createComposedString(int composedIndex, @Nonnull AttributedCharacterIterator text) {
StringBuffer strBuf = new StringBuffer();
// create attributed string with no attributes
for (char c = text.setIndex(composedIndex); c != CharacterIterator.DONE; c = text.next()) {
strBuf.append(c);
}
composedText = new String(strBuf);
}
/**
* Constructs a <code>TextLayout</code> from an iterator over styled text.
* <p>
* The iterator must specify a single paragraph of text because an
* entire paragraph is required for the bidirectional
* algorithm.
* @param text the styled text to display
* @param frc contains information about a graphics device which is needed
* to measure the text correctly.
* Text measurements can vary slightly depending on the
* device resolution, and attributes such as antialiasing. This
* parameter does not specify a translation between the
* <code>TextLayout</code> and user space.
*/
public TextLayout(AttributedCharacterIterator text, FontRenderContext frc) {
if (text == null) {
throw new IllegalArgumentException("Null iterator passed to TextLayout constructor.");
}
int start = text.getBeginIndex();
int limit = text.getEndIndex();
if (start == limit) {
throw new IllegalArgumentException("Zero length iterator passed to TextLayout constructor.");
}
int len = limit - start;
text.first();
char[] chars = new char[len];
int n = 0;
for (char c = text.first();
c != CharacterIterator.DONE;
c = text.next())
{
chars[n++] = c;
}
text.first();
if (text.getRunLimit() == limit) {
Map<? extends Attribute, ?> attributes = text.getAttributes();
Font font = singleFont(chars, 0, len, attributes);
if (font != null) {
fastInit(chars, font, attributes, frc);
return;
}
}
standardInit(text, chars, frc);
}
/**
* @see Graphics2D#drawString(AttributedCharacterIterator, float, float)
*/
@Override
public void drawString(AttributedCharacterIterator iter, float x, float y) {
/*
StringBuffer sb = new StringBuffer();
for(char c = iter.first(); c != AttributedCharacterIterator.DONE; c = iter.next()) {
sb.append(c);
}
drawString(sb.toString(),x,y);
*/
StringBuffer stringbuffer = new StringBuffer(iter.getEndIndex());
for (char c = iter.first(); c != '\uFFFF'; c = iter.next()) {
if (iter.getIndex() == iter.getRunStart()) {
if (stringbuffer.length() > 0) {
drawString(stringbuffer.toString(), x, y);
FontMetrics fontmetrics = getFontMetrics();
x = (float) (x + fontmetrics.getStringBounds(stringbuffer.toString(), this).getWidth());
stringbuffer.delete(0, stringbuffer.length());
}
doAttributes(iter);
}
stringbuffer.append(c);
}
drawString(stringbuffer.toString(), x, y);
underline = false;
}
/**
* Constructs a <code>TextLayout</code> from an iterator over styled text.
* <p>
* The iterator must specify a single paragraph of text because an
* entire paragraph is required for the bidirectional
* algorithm.
* @param text the styled text to display
* @param frc contains information about a graphics device which is needed
* to measure the text correctly.
* Text measurements can vary slightly depending on the
* device resolution, and attributes such as antialiasing. This
* parameter does not specify a translation between the
* <code>TextLayout</code> and user space.
*/
public TextLayout(AttributedCharacterIterator text, FontRenderContext frc) {
if (text == null) {
throw new IllegalArgumentException("Null iterator passed to TextLayout constructor.");
}
int start = text.getBeginIndex();
int limit = text.getEndIndex();
if (start == limit) {
throw new IllegalArgumentException("Zero length iterator passed to TextLayout constructor.");
}
int len = limit - start;
text.first();
char[] chars = new char[len];
int n = 0;
for (char c = text.first();
c != CharacterIterator.DONE;
c = text.next())
{
chars[n++] = c;
}
text.first();
if (text.getRunLimit() == limit) {
Map<? extends Attribute, ?> attributes = text.getAttributes();
Font font = singleFont(chars, 0, len, attributes);
if (font != null) {
fastInit(chars, font, attributes, frc);
return;
}
}
standardInit(text, chars, frc);
}
/**
* Constructs a <code>TextLayout</code> from an iterator over styled text.
* <p>
* The iterator must specify a single paragraph of text because an
* entire paragraph is required for the bidirectional
* algorithm.
* @param text the styled text to display
* @param frc contains information about a graphics device which is needed
* to measure the text correctly.
* Text measurements can vary slightly depending on the
* device resolution, and attributes such as antialiasing. This
* parameter does not specify a translation between the
* <code>TextLayout</code> and user space.
*/
public TextLayout(AttributedCharacterIterator text, FontRenderContext frc) {
if (text == null) {
throw new IllegalArgumentException("Null iterator passed to TextLayout constructor.");
}
int start = text.getBeginIndex();
int limit = text.getEndIndex();
if (start == limit) {
throw new IllegalArgumentException("Zero length iterator passed to TextLayout constructor.");
}
int len = limit - start;
text.first();
char[] chars = new char[len];
int n = 0;
for (char c = text.first();
c != CharacterIterator.DONE;
c = text.next())
{
chars[n++] = c;
}
text.first();
if (text.getRunLimit() == limit) {
Map<? extends Attribute, ?> attributes = text.getAttributes();
Font font = singleFont(chars, 0, len, attributes);
if (font != null) {
fastInit(chars, font, attributes, frc);
return;
}
}
standardInit(text, chars, frc);
}
/**
* Constructs a {@code TextLayout} from an iterator over styled text.
* <p>
* The iterator must specify a single paragraph of text because an
* entire paragraph is required for the bidirectional
* algorithm.
* @param text the styled text to display
* @param frc contains information about a graphics device which is needed
* to measure the text correctly.
* Text measurements can vary slightly depending on the
* device resolution, and attributes such as antialiasing. This
* parameter does not specify a translation between the
* {@code TextLayout} and user space.
*/
public TextLayout(AttributedCharacterIterator text, FontRenderContext frc) {
if (text == null) {
throw new IllegalArgumentException("Null iterator passed to TextLayout constructor.");
}
int start = text.getBeginIndex();
int limit = text.getEndIndex();
if (start == limit) {
throw new IllegalArgumentException("Zero length iterator passed to TextLayout constructor.");
}
int len = limit - start;
text.first();
char[] chars = new char[len];
int n = 0;
for (char c = text.first();
c != CharacterIterator.DONE;
c = text.next())
{
chars[n++] = c;
}
text.first();
if (text.getRunLimit() == limit) {
Map<? extends Attribute, ?> attributes = text.getAttributes();
Font font = singleFont(chars, 0, len, attributes);
if (font != null) {
fastInit(chars, font, attributes, frc);
return;
}
}
standardInit(text, chars, frc);
}
/**
* @tests java.text.AttributedString#AttributedString(java.lang.String)
*/
public void test_ConstructorLjava_lang_String() {
String test = "Test string";
AttributedString attrString = new AttributedString(test);
AttributedCharacterIterator it = attrString.getIterator();
StringBuffer buf = new StringBuffer();
buf.append(it.first());
char ch;
while ((ch = it.next()) != CharacterIterator.DONE)
buf.append(ch);
assertTrue("Wrong string: " + buf, buf.toString().equals(test));
}
public AttributedStringSerializationWrapper(AttributedString as) {
AttributedCharacterIterator iter = as.getIterator();
Set<Attribute> allAttributes = iter.getAllAttributeKeys();
StringBuilder sb = new StringBuilder();
while (true) {
char ch = iter.current();
if (ch == CharacterIterator.DONE)
break;
sb.append(ch);
iter.next();
}
Map<Attribute, List<Run>> runMap = new HashMap<>();
for (Attribute attribute : allAttributes) {
AttributedCharacterIterator iter2 = as
.getIterator(new Attribute[] { attribute });
List<Run> runs = new ArrayList<>();
int index = 0;
while (true) {
if (iter2.current() == CharacterIterator.DONE)
break;
Run lastRun = runs.isEmpty() ? null : runs.get(runs.size() - 1);
Object value = iter2.getAttribute(attribute);
if (lastRun != null && Objects.equals(lastRun.value, value)) {
lastRun.endIndex++;
} else {
Run newRun = new Run(value, index);
runs.add(newRun);
}
index++;
iter2.next();
}
for (Run run : runs) {
for (SerializationFilter filter : AWTSerializationUtils.FILTERS) {
Object filteredValue = filter.filter(run.value);
if (filteredValue != null)
run.value = filteredValue;
}
}
runMap.put(attribute, runs);
}
map.put(KEY_STRING, sb.toString());
map.put(KEY_RUN_MAP, runMap);
}
/**
* Perform the Unicode Bidi algorithm on a given paragraph, as defined in the
* <a href="http://www.unicode.org/unicode/reports/tr9/">Unicode Standard Annex #9</a>,
* version 13,
* also described in The Unicode Standard, Version 4.0 .<p>
*
* This method takes a paragraph of text and computes the
* left-right-directionality of each character. The text should not
* contain any Unicode block separators.<p>
*
* The RUN_DIRECTION attribute in the text, if present, determines the base
* direction (left-to-right or right-to-left). If not present, the base
* direction is computed using the Unicode Bidirectional Algorithm,
* defaulting to left-to-right if there are no strong directional characters
* in the text. This attribute, if present, must be applied to all the text
* in the paragraph.<p>
*
* The BIDI_EMBEDDING attribute in the text, if present, represents
* embedding level information. Negative values from -1 to -62 indicate
* overrides at the absolute value of the level. Positive values from 1 to
* 62 indicate embeddings. Where values are zero or not defined, the base
* embedding level as determined by the base direction is assumed.<p>
*
* The NUMERIC_SHAPING attribute in the text, if present, converts European
* digits to other decimal digits before running the bidi algorithm. This
* attribute, if present, must be applied to all the text in the paragraph.
*
* If the entire text is all of the same directionality, then
* the method may not perform all the steps described by the algorithm,
* i.e., some levels may not be the same as if all steps were performed.
* This is not relevant for unidirectional text.<br>
* For example, in pure LTR text with numbers the numbers would get
* a resolved level of 2 higher than the surrounding text according to
* the algorithm. This implementation may set all resolved levels to
* the same value in such a case.<p>
*
* @param paragraph a paragraph of text with optional character and
* paragraph attribute information
* @stable ICU 3.8
*/
public void setPara(AttributedCharacterIterator paragraph)
{
byte paraLvl;
char ch = paragraph.first();
Boolean runDirection =
(Boolean) paragraph.getAttribute(TextAttributeConstants.RUN_DIRECTION);
Object shaper = paragraph.getAttribute(TextAttributeConstants.NUMERIC_SHAPING);
if (runDirection == null) {
paraLvl = INTERNAL_LEVEL_DEFAULT_LTR;
} else {
paraLvl = (runDirection.equals(TextAttributeConstants.RUN_DIRECTION_LTR)) ?
(byte)Bidi.DIRECTION_LEFT_TO_RIGHT : (byte)Bidi.DIRECTION_RIGHT_TO_LEFT;
}
byte[] lvls = null;
int len = paragraph.getEndIndex() - paragraph.getBeginIndex();
byte[] embeddingLevels = new byte[len];
char[] txt = new char[len];
int i = 0;
while (ch != AttributedCharacterIterator.DONE) {
txt[i] = ch;
Integer embedding =
(Integer) paragraph.getAttribute(TextAttributeConstants.BIDI_EMBEDDING);
if (embedding != null) {
byte level = embedding.byteValue();
if (level == 0) {
/* no-op */
} else if (level < 0) {
lvls = embeddingLevels;
embeddingLevels[i] = (byte)((0 - level) | INTERNAL_LEVEL_OVERRIDE);
} else {
lvls = embeddingLevels;
embeddingLevels[i] = level;
}
}
ch = paragraph.next();
++i;
}
if (shaper != null) {
NumericShapings.shape(shaper, txt, 0, len);
}
setPara(txt, paraLvl, lvls);
}
/**
* Perform the Unicode Bidi algorithm on a given paragraph, as defined in the
* <a href="http://www.unicode.org/unicode/reports/tr9/">Unicode Standard Annex #9</a>,
* version 13,
* also described in The Unicode Standard, Version 4.0 .<p>
*
* This method takes a paragraph of text and computes the
* left-right-directionality of each character. The text should not
* contain any Unicode block separators.<p>
*
* The RUN_DIRECTION attribute in the text, if present, determines the base
* direction (left-to-right or right-to-left). If not present, the base
* direction is computed using the Unicode Bidirectional Algorithm,
* defaulting to left-to-right if there are no strong directional characters
* in the text. This attribute, if present, must be applied to all the text
* in the paragraph.<p>
*
* The BIDI_EMBEDDING attribute in the text, if present, represents
* embedding level information. Negative values from -1 to -62 indicate
* overrides at the absolute value of the level. Positive values from 1 to
* 62 indicate embeddings. Where values are zero or not defined, the base
* embedding level as determined by the base direction is assumed.<p>
*
* The NUMERIC_SHAPING attribute in the text, if present, converts European
* digits to other decimal digits before running the bidi algorithm. This
* attribute, if present, must be applied to all the text in the paragraph.
*
* If the entire text is all of the same directionality, then
* the method may not perform all the steps described by the algorithm,
* i.e., some levels may not be the same as if all steps were performed.
* This is not relevant for unidirectional text.<br>
* For example, in pure LTR text with numbers the numbers would get
* a resolved level of 2 higher than the surrounding text according to
* the algorithm. This implementation may set all resolved levels to
* the same value in such a case.<p>
*
* @param paragraph a paragraph of text with optional character and
* paragraph attribute information
* @stable ICU 3.8
*/
public void setPara(AttributedCharacterIterator paragraph)
{
byte paraLvl;
char ch = paragraph.first();
Boolean runDirection =
(Boolean) paragraph.getAttribute(TextAttributeConstants.RUN_DIRECTION);
Object shaper = paragraph.getAttribute(TextAttributeConstants.NUMERIC_SHAPING);
if (runDirection == null) {
paraLvl = INTERNAL_LEVEL_DEFAULT_LTR;
} else {
paraLvl = (runDirection.equals(TextAttributeConstants.RUN_DIRECTION_LTR)) ?
(byte)Bidi.DIRECTION_LEFT_TO_RIGHT : (byte)Bidi.DIRECTION_RIGHT_TO_LEFT;
}
byte[] lvls = null;
int len = paragraph.getEndIndex() - paragraph.getBeginIndex();
byte[] embeddingLevels = new byte[len];
char[] txt = new char[len];
int i = 0;
while (ch != AttributedCharacterIterator.DONE) {
txt[i] = ch;
Integer embedding =
(Integer) paragraph.getAttribute(TextAttributeConstants.BIDI_EMBEDDING);
if (embedding != null) {
byte level = embedding.byteValue();
if (level == 0) {
/* no-op */
} else if (level < 0) {
lvls = embeddingLevels;
embeddingLevels[i] = (byte)((0 - level) | INTERNAL_LEVEL_OVERRIDE);
} else {
lvls = embeddingLevels;
embeddingLevels[i] = level;
}
}
ch = paragraph.next();
++i;
}
if (shaper != null) {
NumericShapings.shape(shaper, txt, 0, len);
}
setPara(txt, paraLvl, lvls);
}
/**
* Dispatches committed text to a client component.
* Called by composition window.
*
* @param client The component that the text should get dispatched to.
* @param text The iterator providing access to the committed
* (and possible composed) text.
* @param committedCharacterCount The number of committed characters in the text.
*/
synchronized void dispatchCommittedText(Component client,
AttributedCharacterIterator text,
int committedCharacterCount) {
// note that the client is not always the current client component -
// some host input method adapters may dispatch input method events
// through the Java event queue, and we may have switched clients while
// the event was in the queue.
if (committedCharacterCount == 0
|| text.getEndIndex() <= text.getBeginIndex()) {
return;
}
long time = System.currentTimeMillis();
dispatchingCommittedText = true;
try {
InputMethodRequests req = client.getInputMethodRequests();
if (req != null) {
// active client -> send text as InputMethodEvent
int beginIndex = text.getBeginIndex();
AttributedCharacterIterator toBeCommitted =
(new AttributedString(text, beginIndex, beginIndex + committedCharacterCount)).getIterator();
InputMethodEvent inputEvent = new InputMethodEvent(
client,
InputMethodEvent.INPUT_METHOD_TEXT_CHANGED,
toBeCommitted,
committedCharacterCount,
null, null);
client.dispatchEvent(inputEvent);
} else {
// passive client -> send text as KeyEvents
char keyChar = text.first();
while (committedCharacterCount-- > 0 && keyChar != CharacterIterator.DONE) {
KeyEvent keyEvent = new KeyEvent(client, KeyEvent.KEY_TYPED,
time, 0, KeyEvent.VK_UNDEFINED, keyChar);
client.dispatchEvent(keyEvent);
keyChar = text.next();
}
}
} finally {
dispatchingCommittedText = false;
}
}
/**
* Perform the Unicode Bidi algorithm on a given paragraph, as defined in the
* <a href="http://www.unicode.org/unicode/reports/tr9/">Unicode Standard Annex #9</a>,
* version 13,
* also described in The Unicode Standard, Version 4.0 .<p>
*
* This method takes a paragraph of text and computes the
* left-right-directionality of each character. The text should not
* contain any Unicode block separators.<p>
*
* The RUN_DIRECTION attribute in the text, if present, determines the base
* direction (left-to-right or right-to-left). If not present, the base
* direction is computed using the Unicode Bidirectional Algorithm,
* defaulting to left-to-right if there are no strong directional characters
* in the text. This attribute, if present, must be applied to all the text
* in the paragraph.<p>
*
* The BIDI_EMBEDDING attribute in the text, if present, represents
* embedding level information. Negative values from -1 to -62 indicate
* overrides at the absolute value of the level. Positive values from 1 to
* 62 indicate embeddings. Where values are zero or not defined, the base
* embedding level as determined by the base direction is assumed.<p>
*
* The NUMERIC_SHAPING attribute in the text, if present, converts European
* digits to other decimal digits before running the bidi algorithm. This
* attribute, if present, must be applied to all the text in the paragraph.
*
* If the entire text is all of the same directionality, then
* the method may not perform all the steps described by the algorithm,
* i.e., some levels may not be the same as if all steps were performed.
* This is not relevant for unidirectional text.<br>
* For example, in pure LTR text with numbers the numbers would get
* a resolved level of 2 higher than the surrounding text according to
* the algorithm. This implementation may set all resolved levels to
* the same value in such a case.<p>
*
* @param paragraph a paragraph of text with optional character and
* paragraph attribute information
* @stable ICU 3.8
*/
public void setPara(AttributedCharacterIterator paragraph)
{
byte paraLvl;
char ch = paragraph.first();
Boolean runDirection =
(Boolean) paragraph.getAttribute(TextAttributeConstants.RUN_DIRECTION);
Object shaper = paragraph.getAttribute(TextAttributeConstants.NUMERIC_SHAPING);
if (runDirection == null) {
paraLvl = INTERNAL_LEVEL_DEFAULT_LTR;
} else {
paraLvl = (runDirection.equals(TextAttributeConstants.RUN_DIRECTION_LTR)) ?
(byte)Bidi.DIRECTION_LEFT_TO_RIGHT : (byte)Bidi.DIRECTION_RIGHT_TO_LEFT;
}
byte[] lvls = null;
int len = paragraph.getEndIndex() - paragraph.getBeginIndex();
byte[] embeddingLevels = new byte[len];
char[] txt = new char[len];
int i = 0;
while (ch != AttributedCharacterIterator.DONE) {
txt[i] = ch;
Integer embedding =
(Integer) paragraph.getAttribute(TextAttributeConstants.BIDI_EMBEDDING);
if (embedding != null) {
byte level = embedding.byteValue();
if (level == 0) {
/* no-op */
} else if (level < 0) {
lvls = embeddingLevels;
embeddingLevels[i] = (byte)((0 - level) | INTERNAL_LEVEL_OVERRIDE);
} else {
lvls = embeddingLevels;
embeddingLevels[i] = level;
}
}
ch = paragraph.next();
++i;
}
if (shaper != null) {
NumericShapings.shape(shaper, txt, 0, len);
}
setPara(txt, paraLvl, lvls);
}
/**
* Perform the Unicode Bidi algorithm on a given paragraph, as defined in the
* <a href="http://www.unicode.org/unicode/reports/tr9/">Unicode Standard Annex #9</a>,
* version 13,
* also described in The Unicode Standard, Version 4.0 .<p>
*
* This method takes a paragraph of text and computes the
* left-right-directionality of each character. The text should not
* contain any Unicode block separators.<p>
*
* The RUN_DIRECTION attribute in the text, if present, determines the base
* direction (left-to-right or right-to-left). If not present, the base
* direction is computed using the Unicode Bidirectional Algorithm,
* defaulting to left-to-right if there are no strong directional characters
* in the text. This attribute, if present, must be applied to all the text
* in the paragraph.<p>
*
* The BIDI_EMBEDDING attribute in the text, if present, represents
* embedding level information. Negative values from -1 to -62 indicate
* overrides at the absolute value of the level. Positive values from 1 to
* 62 indicate embeddings. Where values are zero or not defined, the base
* embedding level as determined by the base direction is assumed.<p>
*
* The NUMERIC_SHAPING attribute in the text, if present, converts European
* digits to other decimal digits before running the bidi algorithm. This
* attribute, if present, must be applied to all the text in the paragraph.
*
* If the entire text is all of the same directionality, then
* the method may not perform all the steps described by the algorithm,
* i.e., some levels may not be the same as if all steps were performed.
* This is not relevant for unidirectional text.<br>
* For example, in pure LTR text with numbers the numbers would get
* a resolved level of 2 higher than the surrounding text according to
* the algorithm. This implementation may set all resolved levels to
* the same value in such a case.<p>
*
* @param paragraph a paragraph of text with optional character and
* paragraph attribute information
* @stable ICU 3.8
*/
public void setPara(AttributedCharacterIterator paragraph)
{
byte paraLvl;
char ch = paragraph.first();
Boolean runDirection =
(Boolean) paragraph.getAttribute(TextAttributeConstants.RUN_DIRECTION);
Object shaper = paragraph.getAttribute(TextAttributeConstants.NUMERIC_SHAPING);
if (runDirection == null) {
paraLvl = INTERNAL_LEVEL_DEFAULT_LTR;
} else {
paraLvl = (runDirection.equals(TextAttributeConstants.RUN_DIRECTION_LTR)) ?
(byte)Bidi.DIRECTION_LEFT_TO_RIGHT : (byte)Bidi.DIRECTION_RIGHT_TO_LEFT;
}
byte[] lvls = null;
int len = paragraph.getEndIndex() - paragraph.getBeginIndex();
byte[] embeddingLevels = new byte[len];
char[] txt = new char[len];
int i = 0;
while (ch != AttributedCharacterIterator.DONE) {
txt[i] = ch;
Integer embedding =
(Integer) paragraph.getAttribute(TextAttributeConstants.BIDI_EMBEDDING);
if (embedding != null) {
byte level = embedding.byteValue();
if (level == 0) {
/* no-op */
} else if (level < 0) {
lvls = embeddingLevels;
embeddingLevels[i] = (byte)((0 - level) | INTERNAL_LEVEL_OVERRIDE);
} else {
lvls = embeddingLevels;
embeddingLevels[i] = level;
}
}
ch = paragraph.next();
++i;
}
if (shaper != null) {
NumericShapings.shape(shaper, txt, 0, len);
}
setPara(txt, paraLvl, lvls);
}
/**
* Serialises an <code>AttributedString</code> object.
*
* @param as the attributed string object (<code>null</code> permitted).
* @param stream the output stream (<code>null</code> not permitted).
*
* @throws IOException if there is an I/O error.
*/
public static void writeAttributedString(AttributedString as,
ObjectOutputStream stream) throws IOException {
if (stream == null) {
throw new IllegalArgumentException("Null 'stream' argument.");
}
if (as != null) {
stream.writeBoolean(false);
AttributedCharacterIterator aci = as.getIterator();
// build a plain string from aci
// then write the string
StringBuffer plainStr = new StringBuffer();
char current = aci.first();
while (current != CharacterIterator.DONE) {
plainStr = plainStr.append(current);
current = aci.next();
}
stream.writeObject(plainStr.toString());
// then write the attributes and limits for each run
current = aci.first();
int begin = aci.getBeginIndex();
while (current != CharacterIterator.DONE) {
// write the current character - when the reader sees that this
// is not CharacterIterator.DONE, it will know to read the
// run limits and attributes
stream.writeChar(current);
// now write the limit, adjusted as if beginIndex is zero
int limit = aci.getRunLimit();
stream.writeInt(limit - begin);
// now write the attribute set
Map atts = new HashMap(aci.getAttributes());
stream.writeObject(atts);
current = aci.setIndex(limit);
}
// write a character that signals to the reader that all runs
// are done...
stream.writeChar(CharacterIterator.DONE);
}
else {
// write a flag that indicates a null
stream.writeBoolean(true);
}
}
/**
* Dispatches committed text to a client component.
* Called by composition window.
*
* @param client The component that the text should get dispatched to.
* @param text The iterator providing access to the committed
* (and possible composed) text.
* @param committedCharacterCount The number of committed characters in the text.
*/
synchronized void dispatchCommittedText(Component client,
AttributedCharacterIterator text,
int committedCharacterCount) {
// note that the client is not always the current client component -
// some host input method adapters may dispatch input method events
// through the Java event queue, and we may have switched clients while
// the event was in the queue.
if (committedCharacterCount == 0
|| text.getEndIndex() <= text.getBeginIndex()) {
return;
}
long time = System.currentTimeMillis();
dispatchingCommittedText = true;
try {
InputMethodRequests req = client.getInputMethodRequests();
if (req != null) {
// active client -> send text as InputMethodEvent
int beginIndex = text.getBeginIndex();
AttributedCharacterIterator toBeCommitted =
(new AttributedString(text, beginIndex, beginIndex + committedCharacterCount)).getIterator();
InputMethodEvent inputEvent = new InputMethodEvent(
client,
InputMethodEvent.INPUT_METHOD_TEXT_CHANGED,
toBeCommitted,
committedCharacterCount,
null, null);
client.dispatchEvent(inputEvent);
} else {
// passive client -> send text as KeyEvents
char keyChar = text.first();
while (committedCharacterCount-- > 0 && keyChar != CharacterIterator.DONE) {
KeyEvent keyEvent = new KeyEvent(client, KeyEvent.KEY_TYPED,
time, 0, KeyEvent.VK_UNDEFINED, keyChar);
client.dispatchEvent(keyEvent);
keyChar = text.next();
}
}
} finally {
dispatchingCommittedText = false;
}
}