001: /*
002: * @(#)InputMethodEvent.java 1.23 04/06/14
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package java.awt.event;
028:
029: import java.awt.AWTEvent;
030: import java.awt.Component;
031: import java.awt.EventQueue;
032: import java.awt.font.TextHitInfo; //import com.sun.java.swing.font.TextHitInfo;
033: import java.io.IOException;
034: import java.io.ObjectInputStream;
035: import java.lang.Integer;
036: import java.text.AttributedCharacterIterator;
037: import java.text.CharacterIterator;
038:
039: /**
040: * Input method events contain information about text that is being
041: * composed using an input method. Whenever the text changes, the
042: * input method sends an event. If the text component that's currently
043: * using the input method is an active client, the event is dispatched
044: * to that component. Otherwise, it is dispatched to a separate
045: * composition window.
046: *
047: * <p>
048: * The text included with the input method event consists of two parts:
049: * committed text and composed text. Either part may be empty. The two
050: * parts together replace any uncommitted composed text sent in previous events,
051: * or the currently selected committed text.
052: * Committed text should be integrated into the text component's persistent
053: * data, it will not be sent again. Composed text may be sent repeatedly,
054: * with changes to reflect the user's editing operations. Committed text
055: * always precedes composed text.
056: *
057: * @author JavaSoft Asia/Pacific
058: * @version 1.23 06/14/04
059: * @since 1.2
060: */
061:
062: public class InputMethodEvent extends AWTEvent {
063:
064: /**
065: * Serial Version ID.
066: */
067: private static final long serialVersionUID = 4727190874778922661L;
068:
069: /**
070: * Marks the first integer id for the range of input method event ids.
071: */
072: public static final int INPUT_METHOD_FIRST = 1100;
073:
074: /**
075: * The event type indicating changed input method text. This event is
076: * generated by input methods while processing input.
077: */
078: public static final int INPUT_METHOD_TEXT_CHANGED = INPUT_METHOD_FIRST;
079:
080: /**
081: * The event type indicating a changed insertion point in input method text.
082: * This event is
083: * generated by input methods while processing input if only the caret changed.
084: */
085: public static final int CARET_POSITION_CHANGED = INPUT_METHOD_FIRST + 1;
086:
087: /**
088: * Marks the last integer id for the range of input method event ids.
089: */
090: public static final int INPUT_METHOD_LAST = INPUT_METHOD_FIRST + 1;
091:
092: /**
093: * The time stamp that indicates when the event was created.
094: *
095: * @serial
096: * @see #getWhen
097: * @since 1.4
098: */
099: long when;
100:
101: // Text object
102: private transient AttributedCharacterIterator text;
103: private transient int committedCharacterCount;
104: private transient TextHitInfo caret;
105: private transient TextHitInfo visiblePosition;
106:
107: /**
108: * Constructs an <code>InputMethodEvent</code> with the specified
109: * source component, type, time, text, caret, and visiblePosition.
110: * <p>
111: * The offsets of caret and visiblePosition are relative to the current
112: * composed text; that is, the composed text within <code>text</code>
113: * if this is an <code>INPUT_METHOD_TEXT_CHANGED</code> event,
114: * the composed text within the <code>text</code> of the
115: * preceding <code>INPUT_METHOD_TEXT_CHANGED</code> event otherwise.
116: *
117: * @param source the object where the event originated
118: * @param id the event type
119: * @param when a long integer that specifies the time the event occurred
120: * @param text the combined committed and composed text,
121: * committed text first; must be <code>null</code>
122: * when the event type is <code>CARET_POSITION_CHANGED</code>;
123: * may be <code>null</code> for
124: * <code>INPUT_METHOD_TEXT_CHANGED</code> if there's no
125: * committed or composed text
126: * @param committedCharacterCount the number of committed
127: * characters in the text
128: * @param caret the caret (a.k.a. insertion point);
129: * <code>null</code> if there's no caret within current
130: * composed text
131: * @param visiblePosition the position that's most important
132: * to be visible; <code>null</code> if there's no
133: * recommendation for a visible position within current
134: * composed text
135: * @exception IllegalArgumentException if <code>id</code> is not
136: * in the range
137: * <code>INPUT_METHOD_FIRST</code>..<code>INPUT_METHOD_LAST</code>;
138: * or if id is <code>CARET_POSITION_CHANGED</code> and
139: * <code>text</code> is not <code>null</code>;
140: * or if <code>committedCharacterCount</code> is not in the range
141: * <code>0</code>..<code>(text.getEndIndex() - text.getBeginIndex())</code>
142: *
143: * @since 1.4
144: */
145: public InputMethodEvent(Component source, int id, long when,
146: AttributedCharacterIterator text,
147: int committedCharacterCount, TextHitInfo caret,
148: TextHitInfo visiblePosition) {
149: super (source, id);
150: if (id < INPUT_METHOD_FIRST || id > INPUT_METHOD_LAST) {
151: throw new IllegalArgumentException(
152: "id outside of valid range");
153: }
154:
155: if (id == CARET_POSITION_CHANGED && text != null) {
156: throw new IllegalArgumentException(
157: "text must be null for CARET_POSITION_CHANGED");
158: }
159:
160: this .when = when;
161: this .text = text;
162: int textLength = 0;
163: if (text != null) {
164: textLength = text.getEndIndex() - text.getBeginIndex();
165: }
166:
167: if (committedCharacterCount < 0
168: || committedCharacterCount > textLength) {
169: throw new IllegalArgumentException(
170: "committedCharacterCount outside of valid range");
171: }
172: this .committedCharacterCount = committedCharacterCount;
173:
174: this .caret = caret;
175: this .visiblePosition = visiblePosition;
176: }
177:
178: /**
179: * Constructs an <code>InputMethodEvent</code> with the specified
180: * source component, type, text, caret, and visiblePosition.
181: * <p>
182: * The offsets of caret and visiblePosition are relative to the current
183: * composed text; that is, the composed text within <code>text</code>
184: * if this is an <code>INPUT_METHOD_TEXT_CHANGED</code> event,
185: * the composed text within the <code>text</code> of the
186: * preceding <code>INPUT_METHOD_TEXT_CHANGED</code> event otherwise.
187: * The time stamp for this event is initialized by invoking
188: * {@link java.awt.EventQueue#getMostRecentEventTime()}.
189: *
190: * @param source the object where the event originated
191: * @param id the event type
192: * @param text the combined committed and composed text,
193: * committed text first; must be <code>null</code>
194: * when the event type is <code>CARET_POSITION_CHANGED</code>;
195: * may be <code>null</code> for
196: * <code>INPUT_METHOD_TEXT_CHANGED</code> if there's no
197: * committed or composed text
198: * @param committedCharacterCount the number of committed
199: * characters in the text
200: * @param caret the caret (a.k.a. insertion point);
201: * <code>null</code> if there's no caret within current
202: * composed text
203: * @param visiblePosition the position that's most important
204: * to be visible; <code>null</code> if there's no
205: * recommendation for a visible position within current
206: * composed text
207: * @exception IllegalArgumentException if <code>id</code> is not
208: * in the range
209: * <code>INPUT_METHOD_FIRST</code>..<code>INPUT_METHOD_LAST</code>;
210: * or if id is <code>CARET_POSITION_CHANGED</code> and
211: * <code>text</code> is not <code>null</code>;
212: * or if <code>committedCharacterCount</code> is not in the range
213: * <code>0</code>..<code>(text.getEndIndex() - text.getBeginIndex())</code>
214: */
215: public InputMethodEvent(Component source, int id,
216: AttributedCharacterIterator text,
217: int committedCharacterCount, TextHitInfo caret,
218: TextHitInfo visiblePosition) {
219: this (source, id, 0, /*EventQueue.getMostRecentEventTime(),*/
220: text, committedCharacterCount, caret, visiblePosition);
221: }
222:
223: /**
224: * Constructs an <code>InputMethodEvent</code> with the
225: * specified source component, type, caret, and visiblePosition.
226: * The text is set to <code>null</code>,
227: * <code>committedCharacterCount</code> to 0.
228: * <p>
229: * The offsets of <code>caret</code> and <code>visiblePosition</code>
230: * are relative to the current composed text; that is,
231: * the composed text within the <code>text</code> of the
232: * preceding <code>INPUT_METHOD_TEXT_CHANGED</code> event if the
233: * event being constructed as a <code>CARET_POSITION_CHANGED</code> event.
234: * For an <code>INPUT_METHOD_TEXT_CHANGED</code> event without text,
235: * <code>caret</code> and <code>visiblePosition</code> must be
236: * <code>null</code>.
237: * The time stamp for this event is initialized by invoking
238: * {@link java.awt.EventQueue#getMostRecentEventTime()}.
239: *
240: * @param source the object where the event originated
241: * @param id the event type
242: * @param caret the caret (a.k.a. insertion point);
243: * <code>null</code> if there's no caret within current
244: * composed text
245: * @param visiblePosition the position that's most important
246: * to be visible; <code>null</code> if there's no
247: * recommendation for a visible position within current
248: * composed text
249: * @exception IllegalArgumentException if <code>id</code> is not
250: * in the range
251: * <code>INPUT_METHOD_FIRST</code>..<code>INPUT_METHOD_LAST</code>
252: */
253: public InputMethodEvent(Component source, int id,
254: TextHitInfo caret, TextHitInfo visiblePosition) {
255: this (source, id, /*EventQueue.getMostRecentEventTime(),*/null,
256: 0, caret, visiblePosition);
257: }
258:
259: /**
260: * Gets the combined committed and composed text.
261: * Characters from index 0 to index <code>getCommittedCharacterCount() - 1</code> are committed
262: * text, the remaining characters are composed text.
263: *
264: * @return the text.
265: * Always null for CARET_POSITION_CHANGED;
266: * may be null for INPUT_METHOD_TEXT_CHANGED if there's no composed or committed text.
267: */
268: public AttributedCharacterIterator getText() {
269: return text;
270: }
271:
272: /**
273: * Gets the number of committed characters in the text.
274: */
275: public int getCommittedCharacterCount() {
276: return committedCharacterCount;
277: }
278:
279: /**
280: * Gets the caret.
281: * <p>
282: * The offset of the caret is relative to the current
283: * composed text; that is, the composed text within getText()
284: * if this is an <code>INPUT_METHOD_TEXT_CHANGED</code> event,
285: * the composed text within getText() of the
286: * preceding <code>INPUT_METHOD_TEXT_CHANGED</code> event otherwise.
287: *
288: * @return the caret (a.k.a. insertion point).
289: * Null if there's no caret within current composed text.
290: */
291: public TextHitInfo getCaret() {
292: return caret;
293: }
294:
295: /**
296: * Gets the position that's most important to be visible.
297: * <p>
298: * The offset of the visible position is relative to the current
299: * composed text; that is, the composed text within getText()
300: * if this is an <code>INPUT_METHOD_TEXT_CHANGED</code> event,
301: * the composed text within getText() of the
302: * preceding <code>INPUT_METHOD_TEXT_CHANGED</code> event otherwise.
303: *
304: * @return the position that's most important to be visible.
305: * Null if there's no recommendation for a visible position within current composed text.
306: */
307: public TextHitInfo getVisiblePosition() {
308: return visiblePosition;
309: }
310:
311: /**
312: * Consumes this event so that it will not be processed
313: * in the default manner by the source which originated it.
314: */
315: public void consume() {
316: consumed = true;
317: }
318:
319: /**
320: * Returns whether or not this event has been consumed.
321: * @see #consume
322: */
323: public boolean isConsumed() {
324: return consumed;
325: }
326:
327: /**
328: * Returns the time stamp of when this event occurred.
329: *
330: * @return this event's timestamp
331: * @since 1.4
332: */
333: public long getWhen() {
334: return when;
335: }
336:
337: /**
338: * Returns a parameter string identifying this event.
339: * This method is useful for event-logging and for debugging.
340: * It contains the event ID in text form, the characters of the
341: * committed and composed text
342: * separated by "+", the number of committed characters,
343: * the caret, and the visible position.
344: *
345: * @return a string identifying the event and its attributes
346: */
347: public String paramString() {
348: String typeStr;
349: switch (id) {
350: case INPUT_METHOD_TEXT_CHANGED:
351: typeStr = "INPUT_METHOD_TEXT_CHANGED";
352: break;
353: case CARET_POSITION_CHANGED:
354: typeStr = "CARET_POSITION_CHANGED";
355: break;
356: default:
357: typeStr = "unknown type";
358: }
359:
360: String textString;
361: if (text == null) {
362: textString = "no text";
363: } else {
364: StringBuffer textBuffer = new StringBuffer("\"");
365: int committedCharacterCount = this .committedCharacterCount;
366: char c = text.first();
367: while (committedCharacterCount-- > 0) {
368: textBuffer.append(c);
369: c = text.next();
370: }
371: textBuffer.append("\" + \"");
372: while (c != CharacterIterator.DONE) {
373: textBuffer.append(c);
374: c = text.next();
375: }
376: textBuffer.append("\"");
377: textString = textBuffer.toString();
378: }
379:
380: String countString = committedCharacterCount
381: + " characters committed";
382:
383: String caretString;
384: if (caret == null) {
385: caretString = "no caret";
386: } else {
387: caretString = "caret: "; //+ caret.toString();
388: }
389:
390: String visiblePositionString;
391:
392: if (visiblePosition == null) {
393: visiblePositionString = "no visible position";
394: } else {
395: visiblePositionString = "visible position: "; // + visiblePosition.toString();
396: }
397:
398: return typeStr + ", " + textString + ", " + countString + ", "
399: + caretString + ", " + visiblePositionString;
400: }
401:
402: /**
403: * Initializes the <code>when</code> field if it is not present in the
404: * object input stream. In that case, the field will be initialized by
405: * invoking {@link java.awt.EventQueue#getMostRecentEventTime()}.
406: */
407: private void readObject(ObjectInputStream s)
408: throws ClassNotFoundException, IOException {
409: s.defaultReadObject();
410: if (when == 0) {
411: //when = EventQueue.getMostRecentEventTime();
412: }
413: }
414: }
|