| package com.ibm.text.components; |
| |
| import java.awt.*; |
| import java.awt.event.*; |
| import java.text.*; |
| import java.awt.datatransfer.*; |
| import com.ibm.text.*; |
| |
| /** |
| * A subclass of {@link DumbTextComponent} that passes key events through |
| * a {@link com.ibm.text.Transliterator}. |
| * |
| * <p>Copyright © IBM Corporation 1999. All rights reserved. |
| * |
| * @author Alan Liu |
| * @version $RCSfile: TransliteratingTextComponent.java,v $ $Revision: 1.1 $ $Date: 1999/12/20 18:29:21 $ |
| */ |
| public class TransliteratingTextComponent extends DumbTextComponent { |
| |
| private static boolean DEBUG = false; |
| |
| private Transliterator translit = null; |
| |
| // Index into getText() where the start of transliteration is. |
| // As we commit text during keyboardTransliteration, we advance |
| // this. |
| private int start = 0; |
| |
| // Index into getText() where the cursor is; cursor >= start |
| private int cursor = 0; |
| |
| private static final String COPYRIGHT = |
| "\u00A9 IBM Corporation 1999. All rights reserved."; |
| |
| /** |
| * Constructor. |
| */ |
| public TransliteratingTextComponent() { |
| super(); |
| addActionListener(new ActionListener() { |
| public void actionPerformed(ActionEvent e) { |
| // We get an ActionEvent only when the selection changes |
| resetTransliterationStart(); |
| } |
| }); |
| } |
| |
| /** |
| * {@link DumbTextComponent} API. Framework method that is called |
| * when a <code>KeyEvent</code> is received. This implementation |
| * runs the new character through the current |
| * <code>Transliterator</code>, if one is set, and inserts the |
| * transliterated text into the buffer. |
| */ |
| protected void handleKeyTyped(KeyEvent e) { |
| char ch = e.getKeyChar(); |
| |
| if (translit == null) { |
| super.handleKeyTyped(e); |
| return; |
| } |
| |
| // ------------------------------------------------------------ |
| // The following case motivates the two lines that recompute |
| // start and cursor below. |
| |
| // " " |
| // a b c q r|s t u m m |
| // 0 1 2 3 4 5 6 7 8 9 |
| // 0 1 2 |
| |
| // start 3, cursor 5, sel 6 -> { 0, 3, 2 } |
| // : new int[] { 0, sel - start, cursor - start }; |
| |
| // sz>99|9 |
| |
| // " { " |
| // a b c q r 9 9|9 t u m m |
| // 0 1 2 3 4 5 6 7 8 9 a b |
| // 0 1 2 3 4 |
| |
| // { 3, 5, 4 } -> start 6, cursor 7, sel 8 |
| // : start += index[0]; |
| // : cursor = start + index[2] - index[0]; |
| // ------------------------------------------------------------ |
| |
| // Need to save start because calls to replaceRange will update |
| // start and cursor. |
| int saveStart = start; |
| |
| ReplaceableString buf = new ReplaceableString(); |
| buf.getStringBuffer().append(getText().substring(start, |
| getSelectionStart())); |
| |
| int[] index = new int[] { 0, getSelectionStart() - start, |
| cursor - start}; |
| |
| StringBuffer log = null; |
| if (DEBUG) { |
| log = new StringBuffer(); |
| log.append("start " + start + ", cursor " + cursor); |
| log.append(", sel " + getSelectionStart()); |
| log.append(", {" + index[0] + ", " + index[1] + ", " + index[2] + "}, "); |
| log.append('"' + buf.toString() + "\" + '" + ch + "' -> \""); |
| } |
| |
| translit.keyboardTransliterate(buf, index, ch); |
| replaceRange(buf.toString(), start, getSelectionEnd()); |
| // At this point start has been changed by the callback to |
| // resetTransliteratorStart() via replaceRange() -- so use our |
| // local copy, saveStart. |
| |
| // The START index is zero-based. On entry to keyboardTransliterate(), |
| // it was zero. We can therefore just add it to our original |
| // getText()-based index value of start (in saveStart) to get |
| // the new getText()-based start. |
| start = saveStart + index[Transliterator.START]; |
| |
| // Make the cursor getText()-based. The CURSOR index is zero-based. |
| cursor = start + index[Transliterator.CURSOR] |
| - index[Transliterator.START]; |
| |
| if (DEBUG) { |
| String out = buf.toString(); |
| log.append(out.substring(0, index[Transliterator.START])). |
| append('{'). |
| append(out.substring(index[Transliterator.START], |
| index[Transliterator.CURSOR])). |
| append('|'). |
| append(out.substring(index[Transliterator.CURSOR])). |
| append('"'); |
| log.append(", {" + index[0] + ", " + index[1] + ", " + index[2] + "}, "); |
| log.append("start " + start + ", cursor " + cursor); |
| log.append(", sel " + getSelectionStart()); |
| System.out.println(escape(log.toString())); |
| } |
| } |
| |
| /** |
| * Set the {@link com.ibm.text.Transliterator} and direction to |
| * use to process incoming <code>KeyEvent</code>s. |
| * @param t the {@link com.ibm.text.Transliterator} to use |
| */ |
| public void setTransliterator(Transliterator t) { |
| if (translit != t) { // [sic] pointer compare ok; singletons |
| resetTransliterationStart(); |
| } |
| translit = t; |
| } |
| |
| /** |
| * Reset the start point at which transliteration begins. This |
| * needs to be done when the user moves the cursor or when the |
| * current {@link com.ibm.text.Transliterator} is changed. |
| */ |
| private void resetTransliterationStart() { |
| start = getSelectionStart(); |
| cursor = start; |
| } |
| |
| /** |
| * Escape non-ASCII characters as Unicode. |
| * JUST FOR DEBUGGING OUTPUT. |
| */ |
| public static final String escape(String s) { |
| StringBuffer buf = new StringBuffer(); |
| for (int i=0; i<s.length(); ++i) { |
| char c = s.charAt(i); |
| if (c >= ' ' && c <= 0x007F) { |
| if (c == '\\') { |
| buf.append("\\\\"); // That is, "\\" |
| } else { |
| buf.append(c); |
| } |
| } else { |
| buf.append("\\u"); |
| if (c < 0x1000) { |
| buf.append('0'); |
| if (c < 0x100) { |
| buf.append('0'); |
| if (c < 0x10) { |
| buf.append('0'); |
| } |
| } |
| } |
| buf.append(Integer.toHexString(c)); |
| } |
| } |
| return buf.toString(); |
| } |
| } |