/* * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * 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. */ package java.awt.event; import java.awt.AWTEvent; import java.awt.Component; import java.awt.EventQueue; import java.awt.font.TextHitInfo; import java.io.IOException; import java.io.ObjectInputStream; import java.text.AttributedCharacterIterator; import java.text.CharacterIterator; /** * Input method events contain information about text that is being * composed using an input method. Whenever the text changes, the * input method sends an event. If the text component that's currently * using the input method is an active client, the event is dispatched * to that component. Otherwise, it is dispatched to a separate * composition window. * *
* The text included with the input method event consists of two parts:
* committed text and composed text. Either part may be empty. The two
* parts together replace any uncommitted composed text sent in previous events,
* or the currently selected committed text.
* Committed text should be integrated into the text component's persistent
* data, it will not be sent again. Composed text may be sent repeatedly,
* with changes to reflect the user's editing operations. Committed text
* always precedes composed text.
*
* @author JavaSoft Asia/Pacific
* @since 1.2
*/
public class InputMethodEvent extends AWTEvent {
/**
* Serial Version ID.
*/
private static final long serialVersionUID = 4727190874778922661L;
/**
* Marks the first integer id for the range of input method event ids.
*/
public static final int INPUT_METHOD_FIRST = 1100;
/**
* The event type indicating changed input method text. This event is
* generated by input methods while processing input.
*/
public static final int INPUT_METHOD_TEXT_CHANGED = INPUT_METHOD_FIRST;
/**
* The event type indicating a changed insertion point in input method text.
* This event is
* generated by input methods while processing input if only the caret changed.
*/
public static final int CARET_POSITION_CHANGED = INPUT_METHOD_FIRST + 1;
/**
* Marks the last integer id for the range of input method event ids.
*/
public static final int INPUT_METHOD_LAST = INPUT_METHOD_FIRST + 1;
/**
* The time stamp that indicates when the event was created.
*
* @serial
* @see #getWhen
* @since 1.4
*/
long when;
// Text object
private transient AttributedCharacterIterator text;
private transient int committedCharacterCount;
private transient TextHitInfo caret;
private transient TextHitInfo visiblePosition;
/**
* Constructs an InputMethodEvent
with the specified
* source component, type, time, text, caret, and visiblePosition.
*
* The offsets of caret and visiblePosition are relative to the current
* composed text; that is, the composed text within text
* if this is an INPUT_METHOD_TEXT_CHANGED
event,
* the composed text within the text
of the
* preceding INPUT_METHOD_TEXT_CHANGED
event otherwise.
*
Note that passing in an invalid id
results in
* unspecified behavior. This method throws an
* IllegalArgumentException
if source
* is null
.
*
* @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 null
* when the event type is CARET_POSITION_CHANGED
;
* may be null
for
* INPUT_METHOD_TEXT_CHANGED
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);
* null
if there's no caret within current
* composed text
* @param visiblePosition the position that's most important
* to be visible; null
if there's no
* recommendation for a visible position within current
* composed text
* @throws IllegalArgumentException if id
is not
* in the range
* INPUT_METHOD_FIRST
..INPUT_METHOD_LAST
;
* or if id is CARET_POSITION_CHANGED
and
* text
is not null
;
* or if committedCharacterCount
is not in the range
* 0
..(text.getEndIndex() - text.getBeginIndex())
* @throws IllegalArgumentException if source
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;
}
/**
* Constructs an InputMethodEvent
with the specified
* source component, type, text, caret, and visiblePosition.
*
* The offsets of caret and visiblePosition are relative to the current
* composed text; that is, the composed text within text
* if this is an INPUT_METHOD_TEXT_CHANGED
event,
* the composed text within the text
of the
* preceding INPUT_METHOD_TEXT_CHANGED
event otherwise.
* The time stamp for this event is initialized by invoking
* {@link java.awt.EventQueue#getMostRecentEventTime()}.
*
Note that passing in an invalid id
results in
* unspecified behavior. This method throws an
* IllegalArgumentException
if source
* is null
.
*
* @param source the object where the event originated
* @param id the event type
* @param text the combined committed and composed text,
* committed text first; must be null
* when the event type is CARET_POSITION_CHANGED
;
* may be null
for
* INPUT_METHOD_TEXT_CHANGED
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);
* null
if there's no caret within current
* composed text
* @param visiblePosition the position that's most important
* to be visible; null
if there's no
* recommendation for a visible position within current
* composed text
* @throws IllegalArgumentException if id
is not
* in the range
* INPUT_METHOD_FIRST
..INPUT_METHOD_LAST
;
* or if id is CARET_POSITION_CHANGED
and
* text
is not null
;
* or if committedCharacterCount
is not in the range
* 0
..(text.getEndIndex() - text.getBeginIndex())
* @throws IllegalArgumentException if source
is null
*/
public InputMethodEvent(Component source, int id,
AttributedCharacterIterator text, int committedCharacterCount,
TextHitInfo caret, TextHitInfo visiblePosition) {
this(source, id, EventQueue.getMostRecentEventTime(), text,
committedCharacterCount, caret, visiblePosition);
}
/**
* Constructs an InputMethodEvent
with the
* specified source component, type, caret, and visiblePosition.
* The text is set to null
,
* committedCharacterCount
to 0.
*
* The offsets of caret
and visiblePosition
* are relative to the current composed text; that is,
* the composed text within the text
of the
* preceding INPUT_METHOD_TEXT_CHANGED
event if the
* event being constructed as a CARET_POSITION_CHANGED
event.
* For an INPUT_METHOD_TEXT_CHANGED
event without text,
* caret
and visiblePosition
must be
* null
.
* The time stamp for this event is initialized by invoking
* {@link java.awt.EventQueue#getMostRecentEventTime()}.
*
Note that passing in an invalid id
results in
* unspecified behavior. This method throws an
* IllegalArgumentException
if source
* is null
.
*
* @param source the object where the event originated
* @param id the event type
* @param caret the caret (a.k.a. insertion point);
* null
if there's no caret within current
* composed text
* @param visiblePosition the position that's most important
* to be visible; null
if there's no
* recommendation for a visible position within current
* composed text
* @throws IllegalArgumentException if id
is not
* in the range
* INPUT_METHOD_FIRST
..INPUT_METHOD_LAST
* @throws IllegalArgumentException if source
is null
*/
public InputMethodEvent(Component source, int id, TextHitInfo caret,
TextHitInfo visiblePosition) {
this(source, id, EventQueue.getMostRecentEventTime(), null,
0, caret, visiblePosition);
}
/**
* Gets the combined committed and composed text.
* Characters from index 0 to index getCommittedCharacterCount() - 1
are committed
* text, the remaining characters are composed text.
*
* @return the text.
* Always null for CARET_POSITION_CHANGED;
* may be null for INPUT_METHOD_TEXT_CHANGED if there's no composed or committed text.
*/
public AttributedCharacterIterator getText() {
return text;
}
/**
* Gets the number of committed characters in the text.
*/
public int getCommittedCharacterCount() {
return committedCharacterCount;
}
/**
* Gets the caret.
*
* The offset of the caret is relative to the current
* composed text; that is, the composed text within getText()
* if this is an INPUT_METHOD_TEXT_CHANGED
event,
* the composed text within getText() of the
* preceding INPUT_METHOD_TEXT_CHANGED
event otherwise.
*
* @return the caret (a.k.a. insertion point).
* Null if there's no caret within current composed text.
*/
public TextHitInfo getCaret() {
return caret;
}
/**
* Gets the position that's most important to be visible.
*
* The offset of the visible position is relative to the current
* composed text; that is, the composed text within getText()
* if this is an INPUT_METHOD_TEXT_CHANGED
event,
* the composed text within getText() of the
* preceding INPUT_METHOD_TEXT_CHANGED
event otherwise.
*
* @return the position that's most important to be visible.
* Null if there's no recommendation for a visible position within current composed text.
*/
public TextHitInfo getVisiblePosition() {
return visiblePosition;
}
/**
* Consumes this event so that it will not be processed
* in the default manner by the source which originated it.
*/
public void consume() {
consumed = true;
}
/**
* Returns whether or not this event has been consumed.
* @see #consume
*/
public boolean isConsumed() {
return consumed;
}
/**
* Returns the time stamp of when this event occurred.
*
* @return this event's timestamp
* @since 1.4
*/
public long getWhen() {
return when;
}
/**
* Returns a parameter string identifying this event.
* This method is useful for event-logging and for debugging.
* It contains the event ID in text form, the characters of the
* committed and composed text
* separated by "+", the number of committed characters,
* the caret, and the visible position.
*
* @return a string identifying the event and its attributes
*/
public String paramString() {
String typeStr;
switch(id) {
case INPUT_METHOD_TEXT_CHANGED:
typeStr = "INPUT_METHOD_TEXT_CHANGED";
break;
case CARET_POSITION_CHANGED:
typeStr = "CARET_POSITION_CHANGED";
break;
default:
typeStr = "unknown type";
}
String textString;
if (text == null) {
textString = "no text";
} else {
StringBuilder textBuffer = new StringBuilder("\"");
int committedCharacterCount = this.committedCharacterCount;
char c = text.first();
while (committedCharacterCount-- > 0) {
textBuffer.append(c);
c = text.next();
}
textBuffer.append("\" + \"");
while (c != CharacterIterator.DONE) {
textBuffer.append(c);
c = text.next();
}
textBuffer.append("\"");
textString = textBuffer.toString();
}
String countString = committedCharacterCount + " characters committed";
String caretString;
if (caret == null) {
caretString = "no caret";
} else {
caretString = "caret: " + caret.toString();
}
String visiblePositionString;
if (visiblePosition == null) {
visiblePositionString = "no visible position";
} else {
visiblePositionString = "visible position: " + visiblePosition.toString();
}
return typeStr + ", " + textString + ", " + countString + ", " + caretString + ", " + visiblePositionString;
}
/**
* Initializes the when
field if it is not present in the
* object input stream. In that case, the field will be initialized by
* invoking {@link java.awt.EventQueue#getMostRecentEventTime()}.
*/
private void readObject(ObjectInputStream s) throws ClassNotFoundException, IOException {
s.defaultReadObject();
if (when == 0) {
when = EventQueue.getMostRecentEventTime();
}
}
}