下面列出了java.text.AttributedCharacterIterator#getEndIndex ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
/**
* finds attributes with regards to char index in this
* AttributedCharacterIterator, and puts them in a vector
*
* @param iterator
* @return a vector, each entry in this vector are of type FieldContainer ,
* which stores start and end indexes and an attribute this range
* has
*/
private static List<FieldContainer> findFields(AttributedCharacterIterator iterator) {
List<FieldContainer> result = new ArrayList<FieldContainer>();
while (iterator.getIndex() != iterator.getEndIndex()) {
int start = iterator.getRunStart();
int end = iterator.getRunLimit();
Iterator it = iterator.getAttributes().keySet().iterator();
while (it.hasNext()) {
AttributedCharacterIterator.Attribute attribute = (AttributedCharacterIterator.Attribute) it
.next();
Object value = iterator.getAttribute(attribute);
result.add(new FieldContainer(start, end, attribute, value));
// System.out.println(start + " " + end + ": " + attribute + ",
// " + value );
// System.out.println("v.add(new FieldContainer(" + start +"," +
// end +"," + attribute+ "," + value+ "));");
}
iterator.setIndex(end);
}
return result;
}
/**
* 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);
}
}
@Override protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setPaint(getForeground());
g2.setFont(getFont());
SwingUtilities.calculateInnerArea(this, RECT);
float x = RECT.x;
float y = RECT.y;
int w = RECT.width;
AttributedString as = new AttributedString(getText());
as.addAttribute(TextAttribute.FONT, getFont()); // TEST: .deriveFont(at));
// TEST: as.addAttribute(TextAttribute.TRANSFORM, at);
AttributedCharacterIterator aci = as.getIterator();
FontRenderContext frc = g2.getFontRenderContext();
LineBreakMeasurer lbm = new LineBreakMeasurer(aci, frc);
while (lbm.getPosition() < aci.getEndIndex()) {
TextLayout tl = lbm.nextLayout(w);
tl.draw(g2, x, y + tl.getAscent());
y += tl.getDescent() + tl.getLeading() + tl.getAscent();
}
g2.dispose();
}
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");
}
}
/**
* 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);
}
@Override
public void paint(Graphics g, JComponent c) {
if (c.isOpaque()) {
ImageLibrary.drawTiledImage("image.background.FreeColToolTip",
g, c, null);
}
g.setColor(Color.BLACK); // FIXME: find out why this is necessary
Graphics2D graphics = (Graphics2D)g;
float x = margin;
float y = margin;
for (String line : lineBreak.split(((JToolTip) c).getTipText())) {
if (line.isEmpty()) {
y += LEADING;
continue;
}
AttributedCharacterIterator styledText =
new AttributedString(line).getIterator();
LineBreakMeasurer measurer = new LineBreakMeasurer(styledText, frc);
while (measurer.getPosition() < styledText.getEndIndex()) {
TextLayout layout = measurer.nextLayout(maximumWidth);
y += (layout.getAscent());
float dx = layout.isLeftToRight() ?
0 : (maximumWidth - layout.getAdvance());
layout.draw(graphics, x + dx, y);
y += layout.getDescent() + layout.getLeading();
}
}
}
/**
* @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;
}
void rescale(double scale) {
Rectangle bounds = getBounds(scale);
HashMap settings = new HashMap();
settings.put(TextAttribute.FONT, new Font(style.getFontAttributes(scale)));
AttributedCharacterIterator par = (new AttributedString(element.getAttribute("text"), settings)).getIterator();
LineBreakMeasurer lbm = new LineBreakMeasurer(par, new FontRenderContext(null, false, false));
ArrayList drawList = new ArrayList();
int parEnd = par.getEndIndex();
int positionX;
int positionY = bounds.y;
lbm.setPosition(par.getBeginIndex());
while (lbm.getPosition() < parEnd) {
TextLayout layout = lbm.nextLayout(bounds.width);
positionX = bounds.x;
if (!layout.isLeftToRight()) {
positionX += bounds.width - (int) layout.getAdvance();
}
positionY += layout.getAscent();
if (positionY > bounds.y+bounds.height) break;
drawList.add(new Point(positionX, positionY));
drawList.add(layout);
positionY += layout.getDescent() + layout.getLeading();
}
textPositions = new Point[drawList.size()/2];
textLines = new TextLayout[drawList.size()/2];
textScale = scale;
for (int i = 0; i < textPositions.length; i++) {
textPositions[i] = (Point) drawList.get(i*2);
textLines[i] = (TextLayout) drawList.get(i*2+1);
}
}
public void drawString(AttributedCharacterIterator iterator,
int x, int y) {
if (iterator == null) {
throw new NullPointerException("AttributedCharacterIterator is null");
}
if (iterator.getBeginIndex() == iterator.getEndIndex()) {
return; /* nothing to draw */
}
TextLayout tl = new TextLayout(iterator, getFontRenderContext());
tl.draw(this, (float) x, (float) y);
}
/**
* 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);
}
private void replaceInputMethodText(@Nonnull InputMethodEvent e) {
if (myNeedToSelectPreviousChar && SystemInfo.isMac &&
(Registry.is("ide.mac.pressAndHold.brute.workaround") || Registry.is("ide.mac.pressAndHold.workaround") && (hasRelevantCommittedText(e) || e.getCaret() == null))) {
// This is required to support input of accented characters using press-and-hold method (http://support.apple.com/kb/PH11264).
// JDK currently properly supports this functionality only for TextComponent/JTextComponent descendants.
// For our editor component we need this workaround.
// After https://bugs.openjdk.java.net/browse/JDK-8074882 is fixed, this workaround should be replaced with a proper solution.
myNeedToSelectPreviousChar = false;
getCaretModel().runForEachCaret(caret -> {
int caretOffset = caret.getOffset();
if (caretOffset > 0) {
caret.setSelection(caretOffset - 1, caretOffset);
}
});
}
int commitCount = e.getCommittedCharacterCount();
AttributedCharacterIterator text = e.getText();
// old composed text deletion
final Document doc = getDocument();
if (composedText != null) {
if (!isViewer() && doc.isWritable()) {
runUndoTransparent(() -> {
int docLength = doc.getTextLength();
ProperTextRange range = composedTextRange.intersection(new TextRange(0, docLength));
if (range != null) {
doc.deleteString(range.getStartOffset(), range.getEndOffset());
}
});
}
composedText = null;
}
if (text != null) {
text.first();
// committed text insertion
if (commitCount > 0) {
for (char c = text.current(); commitCount > 0; c = text.next(), commitCount--) {
if (c >= 0x20 && c != 0x7F) { // Hack just like in javax.swing.text.DefaultEditorKit.DefaultKeyTypedAction
processKeyTyped(c);
}
}
}
// new composed text insertion
if (!isViewer() && doc.isWritable()) {
int composedTextIndex = text.getIndex();
if (composedTextIndex < text.getEndIndex()) {
createComposedString(composedTextIndex, text);
runUndoTransparent(() -> EditorModificationUtil.insertStringAtCaret(DesktopEditorImpl.this, composedText, false, false));
composedTextRange = ProperTextRange.from(getCaretModel().getOffset(), composedText.length());
}
}
}
}
/**
* Create a new StyledParagraph over the given styled text.
* @param aci an iterator over the text
* @param chars the characters extracted from aci
*/
public StyledParagraph(AttributedCharacterIterator aci,
char[] chars) {
int start = aci.getBeginIndex();
int end = aci.getEndIndex();
length = end - start;
int index = start;
aci.first();
do {
final int nextRunStart = aci.getRunLimit();
final int localIndex = index-start;
Map<? extends Attribute, ?> attributes = aci.getAttributes();
attributes = addInputMethodAttrs(attributes);
Decoration d = Decoration.getDecoration(attributes);
addDecoration(d, localIndex);
Object f = getGraphicOrFont(attributes);
if (f == null) {
addFonts(chars, attributes, localIndex, nextRunStart-start);
}
else {
addFont(f, localIndex);
}
aci.setIndex(nextRunStart);
index = nextRunStart;
} while (index < end);
// Add extra entries to starts arrays with the length
// of the paragraph. 'this' is used as a dummy value
// in the Vector.
if (decorations != null) {
decorationStarts = addToVector(this, length, decorations, decorationStarts);
}
if (fonts != null) {
fontStarts = addToVector(this, length, fonts, fontStarts);
}
}
/**
* Constructs a <code>LineBreakMeasurer</code> for the specified text.
*
* @param text the text for which this <code>LineBreakMeasurer</code>
* produces <code>TextLayout</code> objects; the text must contain
* at least one character; if the text available through
* <code>iter</code> changes, further calls to this
* <code>LineBreakMeasurer</code> instance are undefined (except,
* in some cases, when <code>insertChar</code> or
* <code>deleteChar</code> are invoked afterward - see below)
* @param breakIter the {@link BreakIterator} which defines line
* breaks
* @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>LineBreakMeasurer</code> and user space
* @throws IllegalArgumentException if the text has less than one character
* @see LineBreakMeasurer#insertChar
* @see LineBreakMeasurer#deleteChar
*/
public LineBreakMeasurer(AttributedCharacterIterator text,
BreakIterator breakIter,
FontRenderContext frc) {
if (text.getEndIndex() - text.getBeginIndex() < 1) {
throw new IllegalArgumentException("Text must contain at least one character.");
}
this.breakIter = breakIter;
this.measurer = new TextMeasurer(text, frc);
this.limit = text.getEndIndex();
this.pos = this.start = text.getBeginIndex();
charIter = new CharArrayIterator(measurer.getChars(), this.start);
this.breakIter.setText(charIter);
}
/**
* Constructs a <code>LineBreakMeasurer</code> for the specified text.
*
* @param text the text for which this <code>LineBreakMeasurer</code>
* produces <code>TextLayout</code> objects; the text must contain
* at least one character; if the text available through
* <code>iter</code> changes, further calls to this
* <code>LineBreakMeasurer</code> instance are undefined (except,
* in some cases, when <code>insertChar</code> or
* <code>deleteChar</code> are invoked afterward - see below)
* @param breakIter the {@link BreakIterator} which defines line
* breaks
* @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>LineBreakMeasurer</code> and user space
* @throws IllegalArgumentException if the text has less than one character
* @see LineBreakMeasurer#insertChar
* @see LineBreakMeasurer#deleteChar
*/
public LineBreakMeasurer(AttributedCharacterIterator text,
BreakIterator breakIter,
FontRenderContext frc) {
if (text.getEndIndex() - text.getBeginIndex() < 1) {
throw new IllegalArgumentException("Text must contain at least one character.");
}
this.breakIter = breakIter;
this.measurer = new TextMeasurer(text, frc);
this.limit = text.getEndIndex();
this.pos = this.start = text.getBeginIndex();
charIter = new CharArrayIterator(measurer.getChars(), this.start);
this.breakIter.setText(charIter);
}
/**
* Constructs a <code>LineBreakMeasurer</code> for the specified text.
*
* @param text the text for which this <code>LineBreakMeasurer</code>
* produces <code>TextLayout</code> objects; the text must contain
* at least one character; if the text available through
* <code>iter</code> changes, further calls to this
* <code>LineBreakMeasurer</code> instance are undefined (except,
* in some cases, when <code>insertChar</code> or
* <code>deleteChar</code> are invoked afterward - see below)
* @param breakIter the {@link BreakIterator} which defines line
* breaks
* @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>LineBreakMeasurer</code> and user space
* @throws IllegalArgumentException if the text has less than one character
* @see LineBreakMeasurer#insertChar
* @see LineBreakMeasurer#deleteChar
*/
public LineBreakMeasurer(AttributedCharacterIterator text,
BreakIterator breakIter,
FontRenderContext frc) {
if (text.getEndIndex() - text.getBeginIndex() < 1) {
throw new IllegalArgumentException("Text must contain at least one character.");
}
this.breakIter = breakIter;
this.measurer = new TextMeasurer(text, frc);
this.limit = text.getEndIndex();
this.pos = this.start = text.getBeginIndex();
charIter = new CharArrayIterator(measurer.getChars(), this.start);
this.breakIter.setText(charIter);
}
protected void drawMultilineText(String text, int x, int y, int boxWidth, int boxHeight) {
int availableHeight = boxHeight - ICON_SIZE - ICON_PADDING;
// Create an attributed string based in input text
AttributedString attributedString = new AttributedString(text);
attributedString.addAttribute(TextAttribute.FONT, g.getFont());
attributedString.addAttribute(TextAttribute.FOREGROUND, Color.black);
AttributedCharacterIterator characterIterator = attributedString.getIterator();
int width = boxWidth - (2 * TEXT_PADDING);
int currentHeight = 0;
// Prepare a list of lines of text we'll be drawing
List<TextLayout> layouts = new ArrayList<TextLayout>();
String lastLine = null;
LineBreakMeasurer measurer = new LineBreakMeasurer(characterIterator, g.getFontRenderContext());
TextLayout layout = null;
while (measurer.getPosition() < characterIterator.getEndIndex() && currentHeight <= availableHeight) {
int previousPosition = measurer.getPosition();
// Request next layout
layout = measurer.nextLayout(width);
int height = ((Float) (layout.getDescent() + layout.getAscent() + layout.getLeading())).intValue();
if (currentHeight + height > availableHeight) {
// The line we're about to add should NOT be added anymore, append three dots to previous one instead
// to indicate more text is truncated
layouts.remove(layouts.size() - 1);
if (lastLine.length() >= 4) {
lastLine = lastLine.substring(0, lastLine.length() - 4) + "...";
}
layouts.add(new TextLayout(lastLine, g.getFont(), g.getFontRenderContext()));
} else {
layouts.add(layout);
lastLine = text.substring(previousPosition, measurer.getPosition());
currentHeight += height;
}
}
int currentY = y + ICON_SIZE + ICON_PADDING + ((availableHeight - currentHeight) / 2);
int currentX = 0;
// Actually draw the lines
for (TextLayout textLayout : layouts) {
currentY += textLayout.getAscent();
currentX = TEXT_PADDING + x + ((width - ((Double) textLayout.getBounds().getWidth()).intValue()) / 2);
textLayout.draw(g, currentX, currentY);
currentY += textLayout.getDescent() + textLayout.getLeading();
}
}
/**
* Updates this <code>LineBreakMeasurer</code> after a single
* character is deleted from the text, and sets the current
* position to the beginning of the paragraph.
* @param newParagraph the text after the deletion
* @param deletePos the position in the text at which the character
* is deleted
* @throws IndexOutOfBoundsException if <code>deletePos</code> is
* less than the start of <code>newParagraph</code> or greater
* than the end of <code>newParagraph</code>
* @throws NullPointerException if <code>newParagraph</code> is
* <code>null</code>
* @see #insertChar
*/
public void deleteChar(AttributedCharacterIterator newParagraph,
int deletePos) {
measurer.deleteChar(newParagraph, deletePos);
limit = newParagraph.getEndIndex();
pos = start = newParagraph.getBeginIndex();
charIter.reset(measurer.getChars(), start);
breakIter.setText(charIter);
}
/**
* Updates this <code>LineBreakMeasurer</code> after a single
* character is deleted from the text, and sets the current
* position to the beginning of the paragraph.
* @param newParagraph the text after the deletion
* @param deletePos the position in the text at which the character
* is deleted
* @throws IndexOutOfBoundsException if <code>deletePos</code> is
* less than the start of <code>newParagraph</code> or greater
* than the end of <code>newParagraph</code>
* @throws NullPointerException if <code>newParagraph</code> is
* <code>null</code>
* @see #insertChar
*/
public void deleteChar(AttributedCharacterIterator newParagraph,
int deletePos) {
measurer.deleteChar(newParagraph, deletePos);
limit = newParagraph.getEndIndex();
pos = start = newParagraph.getBeginIndex();
charIter.reset(measurer.getChars(), start);
breakIter.setText(charIter);
}
/**
* Updates this <code>LineBreakMeasurer</code> after a single
* character is deleted from the text, and sets the current
* position to the beginning of the paragraph.
* @param newParagraph the text after the deletion
* @param deletePos the position in the text at which the character
* is deleted
* @throws IndexOutOfBoundsException if <code>deletePos</code> is
* less than the start of <code>newParagraph</code> or greater
* than the end of <code>newParagraph</code>
* @throws NullPointerException if <code>newParagraph</code> is
* <code>null</code>
* @see #insertChar
*/
public void deleteChar(AttributedCharacterIterator newParagraph,
int deletePos) {
measurer.deleteChar(newParagraph, deletePos);
limit = newParagraph.getEndIndex();
pos = start = newParagraph.getBeginIndex();
charIter.reset(measurer.getChars(), start);
breakIter.setText(charIter);
}
/**
* Constructs an <code>InputMethodEvent</code> with the specified
* source component, type, time, text, caret, and visiblePosition.
* <p>
* The offsets of caret and visiblePosition are relative to the current
* composed text; that is, the composed text within <code>text</code>
* if this is an <code>INPUT_METHOD_TEXT_CHANGED</code> event,
* the composed text within the <code>text</code> of the
* preceding <code>INPUT_METHOD_TEXT_CHANGED</code> event otherwise.
* <p>Note that passing in an invalid <code>id</code> results in
* unspecified behavior. This method throws an
* <code>IllegalArgumentException</code> if <code>source</code>
* is <code>null</code>.
*
* @param source the object where the event originated
* @param id the event type
* @param when a long integer that specifies the time the event occurred
* @param text the combined committed and composed text,
* committed text first; must be <code>null</code>
* when the event type is <code>CARET_POSITION_CHANGED</code>;
* may be <code>null</code> for
* <code>INPUT_METHOD_TEXT_CHANGED</code> if there's no
* committed or composed text
* @param committedCharacterCount the number of committed
* characters in the text
* @param caret the caret (a.k.a. insertion point);
* <code>null</code> if there's no caret within current
* composed text
* @param visiblePosition the position that's most important
* to be visible; <code>null</code> if there's no
* recommendation for a visible position within current
* composed text
* @throws IllegalArgumentException if <code>id</code> is not
* in the range
* <code>INPUT_METHOD_FIRST</code>..<code>INPUT_METHOD_LAST</code>;
* or if id is <code>CARET_POSITION_CHANGED</code> and
* <code>text</code> is not <code>null</code>;
* or if <code>committedCharacterCount</code> is not in the range
* <code>0</code>..<code>(text.getEndIndex() - text.getBeginIndex())</code>
* @throws IllegalArgumentException if <code>source</code> is null
*
* @since 1.4
*/
public InputMethodEvent(Component source, int id, long when,
AttributedCharacterIterator text, int committedCharacterCount,
TextHitInfo caret, TextHitInfo visiblePosition) {
super(source, id);
if (id < INPUT_METHOD_FIRST || id > INPUT_METHOD_LAST) {
throw new IllegalArgumentException("id outside of valid range");
}
if (id == CARET_POSITION_CHANGED && text != null) {
throw new IllegalArgumentException("text must be null for CARET_POSITION_CHANGED");
}
this.when = when;
this.text = text;
int textLength = 0;
if (text != null) {
textLength = text.getEndIndex() - text.getBeginIndex();
}
if (committedCharacterCount < 0 || committedCharacterCount > textLength) {
throw new IllegalArgumentException("committedCharacterCount outside of valid range");
}
this.committedCharacterCount = committedCharacterCount;
this.caret = caret;
this.visiblePosition = visiblePosition;
}