001/* InputMethodEvent.java -- events from a text input method
002   Copyright (C) 1999, 2002, 2005  Free Software Foundation, Inc.
003
004This file is part of GNU Classpath.
005
006GNU Classpath is free software; you can redistribute it and/or modify
007it under the terms of the GNU General Public License as published by
008the Free Software Foundation; either version 2, or (at your option)
009any later version.
010
011GNU Classpath is distributed in the hope that it will be useful, but
012WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014General Public License for more details.
015
016You should have received a copy of the GNU General Public License
017along with GNU Classpath; see the file COPYING.  If not, write to the
018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
01902110-1301 USA.
020
021Linking this library statically or dynamically with other modules is
022making a combined work based on this library.  Thus, the terms and
023conditions of the GNU General Public License cover the whole
024combination.
025
026As a special exception, the copyright holders of this library give you
027permission to link this library with independent modules to produce an
028executable, regardless of the license terms of these independent
029modules, and to copy and distribute the resulting executable under
030terms of your choice, provided that you also meet, for each linked
031independent module, the terms and conditions of the license of that
032module.  An independent module is a module which is not derived from
033or based on this library.  If you modify this library, you may extend
034this exception to your version of the library, but you are not
035obligated to do so.  If you do not wish to do so, delete this
036exception statement from your version. */
037
038
039package java.awt.event;
040
041import gnu.java.lang.CPStringBuilder;
042
043import java.awt.AWTEvent;
044import java.awt.Component;
045import java.awt.EventQueue;
046import java.awt.font.TextHitInfo;
047import java.io.IOException;
048import java.io.ObjectInputStream;
049import java.text.AttributedCharacterIterator;
050
051/**
052 * This class is for event generated by change in a text input method.
053 *
054 * @author Aaron M. Renn (arenn@urbanophile.com)
055 * @see InputMethodListener
056 * @since 1.2
057 * @status updated to 1.4
058 */
059public class InputMethodEvent extends AWTEvent
060{
061  /**
062   * Compatible with JDK 1.2+.
063   */
064  private static final long serialVersionUID = 4727190874778922661L;
065
066  /** This is the first id in the range of event ids used by this class. */
067  public static final int INPUT_METHOD_FIRST = 1100;
068
069  /** This event id indicates that the text in the input method has changed. */
070  public static final int INPUT_METHOD_TEXT_CHANGED = 1100;
071
072  /** This event id indicates that the input method curor point has changed. */
073  public static final int CARET_POSITION_CHANGED = 1101;
074
075  /** This is the last id in the range of event ids used by this class. */
076  public static final int INPUT_METHOD_LAST = 1101;
077
078  /**
079   * The timestamp when this event was created.
080   *
081   * @serial the timestamp
082   * @since 1.4
083   */
084  private long when;
085
086  /** The input method text. */
087  private final transient AttributedCharacterIterator text;
088
089  /** The number of committed characters in the text. */
090  private final transient int committedCharacterCount;
091
092  /** The caret. */
093  private final transient TextHitInfo caret;
094
095  /** The most important position to be visible. */
096  private final transient TextHitInfo visiblePosition;
097
098  /**
099   * Initializes a new instance of <code>InputMethodEvent</code> with the
100   * specified source, id, timestamp, text, char count, caret, and visible
101   * position.
102   *
103   * @param source the source that generated the event
104   * @param id the event id
105   * @param when the timestamp of the event
106   * @param text the input text
107   * @param committedCharacterCount the number of committed characters
108   * @param caret the caret position
109   * @param visiblePosition the position most important to make visible
110   * @throws IllegalArgumentException if source is null, id is invalid, id is
111   *         CARET_POSITION_CHANGED and text is non-null, or if
112   *         committedCharacterCount is out of range
113   * @since 1.4
114   */
115  public InputMethodEvent(Component source, int id, long when,
116                          AttributedCharacterIterator text,
117                          int committedCharacterCount, TextHitInfo caret,
118                          TextHitInfo visiblePosition)
119  {
120    super(source, id);
121    this.when = when;
122    this.text = text;
123    this.committedCharacterCount = committedCharacterCount;
124    this.caret = caret;
125    this.visiblePosition = visiblePosition;
126    if (id < INPUT_METHOD_FIRST || id > INPUT_METHOD_LAST
127        || (id == CARET_POSITION_CHANGED && text != null)
128        || committedCharacterCount < 0
129        || (committedCharacterCount
130            > (text == null ? 0 : text.getEndIndex() - text.getBeginIndex())))
131      throw new IllegalArgumentException();
132  }
133
134  /**
135   * Initializes a new instance of <code>InputMethodEvent</code> with the
136   * specified source, id, text, char count, caret, and visible position.
137   *
138   * @param source the source that generated the event
139   * @param id the event id
140   * @param text the input text
141   * @param committedCharacterCount the number of committed characters
142   * @param caret the caret position
143   * @param visiblePosition the position most important to make visible
144   * @throws IllegalArgumentException if source is null, id is invalid, id is
145   *         CARET_POSITION_CHANGED and text is non-null, or if
146   *         committedCharacterCount is out of range
147   * @since 1.4
148   */
149  public InputMethodEvent(Component source, int id,
150                          AttributedCharacterIterator text,
151                          int committedCharacterCount, TextHitInfo caret,
152                          TextHitInfo visiblePosition)
153  {
154    this(source, id, EventQueue.getMostRecentEventTime(), text,
155         committedCharacterCount, caret, visiblePosition);
156  }
157
158  /**
159   * Initializes a new instance of <code>InputMethodEvent</code> with the
160   * specified source, id, caret, and visible position, and with a null
161   * text and char count.
162   *
163   * @param source the source that generated the event
164   * @param id the event id
165   * @param caret the caret position
166   * @param visiblePosition the position most important to make visible
167   * @throws IllegalArgumentException if source is null or id is invalid
168   * @since 1.4
169   */
170  public InputMethodEvent(Component source, int id, TextHitInfo caret,
171                          TextHitInfo visiblePosition)
172  {
173    this(source, id, EventQueue.getMostRecentEventTime(), null, 0, caret,
174         visiblePosition);
175  }
176
177  /**
178   * This method returns the input method text. This can be <code>null</code>,
179   * and will always be null for <code>CARET_POSITION_CHANGED</code> events.
180   * Characters from 0 to <code>getCommittedCharacterCount()-1</code> have
181   * been committed, the remaining characters are composed text.
182   *
183   * @return the input method text, or null
184   */
185  public AttributedCharacterIterator getText()
186  {
187    return text;
188  }
189
190  /**
191   * Returns the number of committed characters in the input method text.
192   *
193   * @return the number of committed characters in the input method text
194   */
195  public int getCommittedCharacterCount()
196  {
197    return committedCharacterCount;
198  }
199
200  /**
201   * Returns the caret position. The caret offset is relative to the composed
202   * text of the most recent <code>INPUT_METHOD_TEXT_CHANGED</code> event.
203   *
204   * @return the caret position, or null
205   */
206  public TextHitInfo getCaret()
207  {
208    return caret;
209  }
210
211  /**
212   * Returns the position that is most important to be visible, or null if
213   * such a hint is not necessary. The caret offset is relative to the composed
214   * text of the most recent <code>INPUT_METHOD_TEXT_CHANGED</code> event.
215   *
216   * @return the position that is most important to be visible
217   */
218  public TextHitInfo getVisiblePosition()
219  {
220    return visiblePosition;
221  }
222
223  /**
224   * This method consumes the event.  A consumed event is not processed
225   * in the default manner by the component that generated it.
226   */
227  public void consume()
228  {
229    consumed = true;
230  }
231
232  /**
233   * This method tests whether or not this event has been consumed.
234   *
235   * @return true if the event has been consumed
236   */
237  public boolean isConsumed()
238  {
239    return consumed;
240  }
241
242  /**
243   * Return the timestamp of this event.
244   *
245   * @return the timestamp
246   * @since 1.4
247   */
248  public long getWhen()
249  {
250    return when;
251  }
252
253  /**
254   * This method returns a string identifying the event. This contains the
255   * event ID, the committed and composed characters separated by '+', the
256   * number of committed characters, the caret, and the visible position.
257   *
258   * @return a string identifying the event
259   */
260  public String paramString()
261  {
262    CPStringBuilder s
263      = new CPStringBuilder(80 + (text == null ? 0
264                               : text.getEndIndex() - text.getBeginIndex()));
265    s.append(id == INPUT_METHOD_TEXT_CHANGED ? "INPUT_METHOD_TEXT_CHANGED, "
266             : "CARET_POSITION_CHANGED, ");
267    if (text == null)
268      s.append("no text, 0 characters committed, caret: ");
269    else
270      {
271        s.append('"');
272        int i = text.getBeginIndex();
273        int j = committedCharacterCount;
274        while (--j >= 0)
275          s.append(text.setIndex(i++));
276        s.append("\" + \"");
277        j = text.getEndIndex() - i;
278        while (--j >= 0)
279          s.append(text.setIndex(i++));
280        s.append("\", ").append(committedCharacterCount)
281          .append(" characters committed, caret: ");          
282      }
283    s.append(caret == null ? (Object) "no caret" : caret).append(", ")
284      .append(visiblePosition == null ? (Object) "no visible position"
285              : visiblePosition);
286    return s.toString();
287  }
288
289  /**
290   * Reads in the object from a serial stream, updating when to
291   * {@link EventQueue#getMostRecentEventTime()} if necessary.
292   *
293   * @param s the stream to read from
294   * @throws IOException if deserialization fails
295   * @throws ClassNotFoundException if deserialization fails
296   * @serialData default, except for updating when
297   */
298  private void readObject(ObjectInputStream s)
299    throws IOException, ClassNotFoundException
300  {
301    s.defaultReadObject();
302    if (when == 0)
303      when = EventQueue.getMostRecentEventTime();
304  }
305} // class InputMethodEvent