1. /*
  2. * @(#)InputMethodEvent.java 1.13 01/11/29
  3. *
  4. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.awt.event;
  8. import java.awt.AWTEvent;
  9. import java.awt.Component;
  10. import java.lang.Integer;
  11. import java.awt.font.TextHitInfo;
  12. import java.text.AttributedCharacterIterator;
  13. import java.text.CharacterIterator;
  14. /**
  15. * Input method events contain information about text that is being
  16. * composed using an input method. Whenever the text changes, the
  17. * input method sends an event. If the text component that's currently
  18. * using the input method is an active client, the event is dispatched
  19. * to that component. Otherwise, it is dispatched to a separate
  20. * composition window.
  21. *
  22. * <p>
  23. * The text included with the input method event consists of two parts:
  24. * committed text and composed text. Either part may be empty. The two
  25. * parts together replace any uncommitted composed text sent in previous events,
  26. * or the currently selected committed text.
  27. * Committed text should be integrated into the text component's persistent
  28. * data, it will not be sent again. Composed text may be sent repeatedly,
  29. * with changes to reflect the user's editing operations. Committed text
  30. * always precedes composed text.
  31. *
  32. * @version 1.13 11/29/01
  33. * @author JavaSoft Asia/Pacific
  34. */
  35. public class InputMethodEvent extends AWTEvent {
  36. /**
  37. * Marks the first integer id for the range of input method event ids.
  38. */
  39. public static final int INPUT_METHOD_FIRST = 1100;
  40. /**
  41. * The event type indicating changed input method text. This event is
  42. * generated by input methods while processing input.
  43. */
  44. public static final int INPUT_METHOD_TEXT_CHANGED = INPUT_METHOD_FIRST;
  45. /**
  46. * The event type indicating a changed insertion point in input method text.
  47. * This event is
  48. * generated by input methods while processing input if only the caret changed.
  49. */
  50. public static final int CARET_POSITION_CHANGED = INPUT_METHOD_FIRST + 1;
  51. /**
  52. * Marks the last integer id for the range of input method event ids.
  53. */
  54. public static final int INPUT_METHOD_LAST = INPUT_METHOD_FIRST + 1;
  55. // Text object
  56. private transient AttributedCharacterIterator text;
  57. private transient int committedCharacterCount;
  58. private transient TextHitInfo caret;
  59. private transient TextHitInfo visiblePosition;
  60. /**
  61. * Constructs an InputMethodEvent with the specified source component, type,
  62. * text, caret, and visiblePosition.
  63. * <p>
  64. * The offsets of caret and visiblePosition are relative to the current
  65. * composed text; that is, the composed text within <code>text</code>
  66. * if this is an <code>INPUT_METHOD_TEXT_CHANGED</code> event,
  67. * the composed text within the <code>text</code> of the
  68. * preceding <code>INPUT_METHOD_TEXT_CHANGED</code> event otherwise.
  69. *
  70. * @param source The object where the event originated.
  71. * @param id The event type.
  72. * @param text The combined committed and composed text, committed text first.
  73. * Always null for <code>CARET_POSITION_CHANGED</code>
  74. * may be null for <code>INPUT_METHOD_TEXT_CHANGED</code> if there's no committed or composed text.
  75. * @param committedCharacterCount The number of committed characters in the text.
  76. * @param caret the caret (a.k.a. insertion point).
  77. * Null if there's no caret within current composed text.
  78. * @param visiblePosition The position that's most important to be visible.
  79. * Null if there's no recommendation for a visible position within current composed text.
  80. * @exception IllegalArgumentException
  81. * if <code>id</code> is not in the range <code>INPUT_METHOD_FIRST</code>..<code>INPUT_METHOD_LAST</code>,
  82. * if id is <code>CARET_POSITION_CHANGED</code> and <code>text</code> is not null,
  83. * or if <code>committedCharacterCount</code> is not in the range <code>0</code>..<code>(text.getEndIndex() - text.getBeginIndex())</code>
  84. */
  85. public InputMethodEvent(Component source, int id,
  86. AttributedCharacterIterator text, int committedCharacterCount,
  87. TextHitInfo caret, TextHitInfo visiblePosition) {
  88. super(source, id);
  89. if (id < INPUT_METHOD_FIRST || id > INPUT_METHOD_LAST) {
  90. throw new IllegalArgumentException("id outside of valid range");
  91. }
  92. if (id == CARET_POSITION_CHANGED && text != null) {
  93. throw new IllegalArgumentException("text must be null for CARET_POSITION_CHANGED");
  94. }
  95. this.text = text;
  96. int textLength = 0;
  97. if (text != null) {
  98. textLength = text.getEndIndex() - text.getBeginIndex();
  99. }
  100. if (committedCharacterCount < 0 || committedCharacterCount > textLength) {
  101. throw new IllegalArgumentException("committedCharacterCount outside of valid range");
  102. }
  103. this.committedCharacterCount = committedCharacterCount;
  104. this.caret = caret;
  105. this.visiblePosition = visiblePosition;
  106. }
  107. /**
  108. * Constructs an InputMethodEvent with the specified source component, type,
  109. * caret, and visiblePosition. The text is set to null, committedCharacterCount to 0.
  110. * <p>
  111. * The offsets of caret and visiblePosition are relative to the current
  112. * composed text; that is,
  113. * the composed text within the <code>text</code> of the
  114. * preceding <code>INPUT_METHOD_TEXT_CHANGED</code> event
  115. * if the event being constructed as a <code>CARET_POSITION_CHANGED</code> event.
  116. * For an <code>INPUT_METHOD_TEXT_CHANGED</code> event without text, caret
  117. * and visiblePosition must be null.
  118. *
  119. * @param source The object where the event originated.
  120. * @param id The event type.
  121. * @param caret the caret (a.k.a. insertion point).
  122. * Null if there's no caret within current composed text.
  123. * @param visiblePosition The position that's most important to be visible.
  124. * Null if there's no recommendation for a visible position within current composed text.
  125. */
  126. public InputMethodEvent(Component source, int id, TextHitInfo caret,
  127. TextHitInfo visiblePosition) {
  128. this(source, id, null, 0, caret, visiblePosition);
  129. }
  130. /**
  131. * Gets the combined committed and composed text.
  132. * Characters from index 0 to index <code>getCommittedCharacterCount() - 1</code> are committed
  133. * text, the remaining characters are composed text.
  134. *
  135. * @return the text.
  136. * Always null for CARET_POSITION_CHANGED;
  137. * may be null for INPUT_METHOD_TEXT_CHANGED if there's no composed or committed text.
  138. */
  139. public AttributedCharacterIterator getText() {
  140. return text;
  141. }
  142. /**
  143. * Gets the number of committed characters in the text.
  144. */
  145. public int getCommittedCharacterCount() {
  146. return committedCharacterCount;
  147. }
  148. /**
  149. * Gets the caret.
  150. * <p>
  151. * The offset of the caret is relative to the current
  152. * composed text; that is, the composed text within getText()
  153. * if this is an <code>INPUT_METHOD_TEXT_CHANGED</code> event,
  154. * the composed text within getText() of the
  155. * preceding <code>INPUT_METHOD_TEXT_CHANGED</code> event otherwise.
  156. *
  157. * @return the caret (a.k.a. insertion point).
  158. * Null if there's no caret within current composed text.
  159. */
  160. public TextHitInfo getCaret() {
  161. return caret;
  162. }
  163. /**
  164. * Gets the position that's most important to be visible.
  165. * <p>
  166. * The offset of the visible position is relative to the current
  167. * composed text; that is, the composed text within getText()
  168. * if this is an <code>INPUT_METHOD_TEXT_CHANGED</code> event,
  169. * the composed text within getText() of the
  170. * preceding <code>INPUT_METHOD_TEXT_CHANGED</code> event otherwise.
  171. *
  172. * @return the position that's most important to be visible.
  173. * Null if there's no recommendation for a visible position within current composed text.
  174. */
  175. public TextHitInfo getVisiblePosition() {
  176. return visiblePosition;
  177. }
  178. /**
  179. * Consumes this event so that it will not be processed
  180. * in the default manner by the source which originated it.
  181. */
  182. public void consume() {
  183. consumed = true;
  184. }
  185. /**
  186. * Returns whether or not this event has been consumed.
  187. * @see #consume
  188. */
  189. public boolean isConsumed() {
  190. return consumed;
  191. }
  192. /**
  193. * Returns a parameter string identifying this event.
  194. * This method is useful for event-logging and for debugging.
  195. * It contains the event ID in text form, the characters of the
  196. * committed and composed text
  197. * separated by "+", the number of committed characters,
  198. * the caret, and the visible position.
  199. *
  200. * @return a string identifying the event and its attributes
  201. */
  202. public String paramString() {
  203. String typeStr;
  204. switch(id) {
  205. case INPUT_METHOD_TEXT_CHANGED:
  206. typeStr = "INPUT_METHOD_TEXT_CHANGED";
  207. break;
  208. case CARET_POSITION_CHANGED:
  209. typeStr = "CARET_POSITION_CHANGED";
  210. break;
  211. default:
  212. typeStr = "unknown type";
  213. }
  214. String textString;
  215. if (text == null) {
  216. textString = "no text";
  217. } else {
  218. StringBuffer textBuffer = new StringBuffer("\"");
  219. int committedCharacterCount = this.committedCharacterCount;
  220. char c = text.first();
  221. while (committedCharacterCount-- > 0) {
  222. textBuffer.append(c);
  223. c = text.next();
  224. }
  225. textBuffer.append("\" + \"");
  226. while (c != CharacterIterator.DONE) {
  227. textBuffer.append(c);
  228. c = text.next();
  229. }
  230. textBuffer.append("\"");
  231. textString = textBuffer.toString();
  232. }
  233. String countString = committedCharacterCount + " characters committed";
  234. String caretString;
  235. if (caret == null) {
  236. caretString = "no caret";
  237. } else {
  238. caretString = "caret: " + caret.toString();
  239. }
  240. String visiblePositionString;
  241. if (visiblePosition == null) {
  242. visiblePositionString = "no visible position";
  243. } else {
  244. visiblePositionString = "visible position: " + visiblePosition.toString();
  245. }
  246. return typeStr + ", " + textString + ", " + countString + ", " + caretString + ", " + visiblePositionString;
  247. }
  248. }