1 // 2016 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html#License 3 /* 4 ******************************************************************************* 5 * Copyright (C) 1996-2010, International Business Machines Corporation and * 6 * others. All Rights Reserved. * 7 ******************************************************************************* 8 */ 9 package com.ibm.icu.dev.demo.translit; 10 11 import java.awt.event.KeyEvent; 12 13 import com.ibm.icu.dev.demo.impl.DumbTextComponent; 14 import com.ibm.icu.text.ReplaceableString; 15 import com.ibm.icu.text.Transliterator; 16 17 /** 18 * A subclass of {@link DumbTextComponent} that passes key events through 19 * a {@link com.ibm.icu.text.Transliterator}. 20 * 21 * @author Alan Liu 22 */ 23 public class TransliteratingTextComponent extends DumbTextComponent { 24 25 /** 26 * For serialization 27 */ 28 private static final long serialVersionUID = -8672128213174154047L; 29 30 private static boolean DEBUG = false; 31 32 private Transliterator translit = null; 33 34 // NOTE: DISABLE THE START AND CURSOR UNTIL WE CAN GET IT TO WORK AT ALL 35 36 // Index into getText() where the start of transliteration is. 37 // As we commit text during transliteration, we advance 38 // this. 39 //private int start = 0; 40 41 // Index into getText() where the cursor is; cursor >= start 42 //private int cursor = 0; 43 44 // private static final String COPYRIGHT = 45 // "\u00A9 IBM Corporation 1999. All rights reserved."; 46 47 /** 48 * Constructor. 49 */ 50 public TransliteratingTextComponent() { 51 super(); 52 /* 53 addActionListener(new ActionListener() { 54 public void actionPerformed(ActionEvent e) { 55 // We get an ActionEvent only when the selection changes 56 resetTransliterationStart(); 57 } 58 }); 59 */ 60 } 61 62 /** 63 * {@link DumbTextComponent} API. Framework method that is called 64 * when a <code>KeyEvent</code> is received. This implementation 65 * runs the new character through the current 66 * <code>Transliterator</code>, if one is set, and inserts the 67 * transliterated text into the buffer. 68 */ 69 protected void handleKeyTyped(KeyEvent e) { 70 char ch = e.getKeyChar(); 71 72 if (translit == null) { 73 setKeyStart(-1); 74 super.handleKeyTyped(e); 75 return; 76 } 77 78 transliterate(ch, false); 79 } 80 81 public void flush() { 82 if (translit != null) transliterate('\uFFFF', true); 83 } 84 85 86 protected void transliterate(char ch, boolean flush) { 87 88 // ------------------------------------------------------------ 89 // The following case motivates the two lines that recompute 90 // start and cursor below. 91 92 // " " 93 // a b c q r|s t u m m 94 // 0 1 2 3 4 5 6 7 8 9 95 // 0 1 2 96 97 // start 3, cursor 5, sel 6 -> { 0, 3, 2 } 98 // : new int[] { 0, sel - start, cursor - start }; 99 100 // sz>99|9 101 102 // " { " 103 // a b c q r 9 9|9 t u m m 104 // 0 1 2 3 4 5 6 7 8 9 a b 105 // 0 1 2 3 4 106 107 // { 3, 5, 4 } -> start 6, cursor 7, sel 8 108 // : start += index[0]; 109 // : cursor = start + index[2] - index[0]; 110 // ------------------------------------------------------------ 111 112 // Need to save start because calls to replaceRange will update 113 // start and cursor. 114 //int saveStart = start; 115 116 int end = flush ? getSelectionEnd() : getSelectionStart(); 117 String sourceText = getText().substring(0,end); 118 ReplaceableString buf = new ReplaceableString(sourceText); 119 /*buf.replace(0, 1, getText().substring(start, 120 getSelectionStart()));*/ 121 122 Transliterator.Position index = new Transliterator.Position(); 123 index.contextLimit = buf.length(); 124 index.contextStart = 0; 125 index.start = getKeyStart(); 126 if (index.start == -1) index.start = getSelectionStart(); 127 index.limit = buf.length(); 128 129 // StringBuffer log = null; 130 if (DEBUG) { 131 System.out.println("Transliterator: " + translit.getID()); 132 System.out.println("From:\t" + '"' + buf.toString() + '"' 133 + "; {cs: " + index.contextStart 134 + ", s: " + index.start 135 + ", l: " + index.limit 136 + ", cl: " + index.contextLimit 137 + "}" + "; '" + ch + "'" 138 + " " + getKeyStart() 139 ); 140 } 141 142 if (flush) { 143 translit.finishTransliteration(buf, index); 144 } else { 145 translit.transliterate(buf, index, ch); 146 } 147 148 if (DEBUG) { 149 System.out.println("To:\t" + '"' + buf.toString() + '"' 150 + "; {cs: " + index.contextStart 151 + ", s: " + index.start 152 + ", l: " + index.limit 153 + ", cl: " + index.contextLimit 154 + "}" 155 ); 156 System.out.println(); 157 } 158 /* 159 buf.replace(buf.length(), buf.length(), String.valueOf(ch)); 160 translit.transliterate(buf); 161 */ 162 163 String result = buf.toString(); 164 //if (result.equals(sourceText + ch)) return; 165 166 replaceRange(result, 0, getSelectionEnd()); 167 setKeyStart(index.start); 168 169 // At this point start has been changed by the callback to 170 // resetTransliteratorStart() via replaceRange() -- so use our 171 // local copy, saveStart. 172 173 // The START index is zero-based. On entry to transliterate(), 174 // it was zero. We can therefore just add it to our original 175 // getText()-based index value of start (in saveStart) to get 176 // the new getText()-based start. 177 // start = saveStart + index.contextStart; 178 179 // Make the cursor getText()-based. The CURSOR index is zero-based. 180 // cursor = start + index.start - index.contextStart; 181 182 /* 183 if (DEBUG) { 184 String out = buf.toString(); 185 log.append(out.substring(0, index.contextStart)). 186 append('{'). 187 append(out.substring(index.contextStart, index.start)). 188 append('|'). 189 append(out.substring(index.start)). 190 append('"'); 191 log.append(", {" + index.contextStart + ", " + index.contextLimit + ", " + index.start + "}, "); 192 // log.append("start " + start + ", cursor " + cursor); 193 log.append(", sel " + getSelectionStart()); 194 System.out.println(escape(log.toString())); 195 } 196 */ 197 } 198 199 /** 200 * Set the {@link com.ibm.icu.text.Transliterator} and direction to 201 * use to process incoming <code>KeyEvent</code>s. 202 * @param t the {@link com.ibm.icu.text.Transliterator} to use 203 */ 204 public void setTransliterator(Transliterator t) { 205 /* 206 if (translit != t) { // [sic] pointer compare ok; singletons 207 resetTransliterationStart(); 208 } 209 */ 210 translit = t; 211 } 212 213 public Transliterator getTransliterator() { 214 return translit; 215 } 216 217 /** 218 * Reset the start point at which transliteration begins. This 219 * needs to be done when the user moves the cursor or when the 220 * current {@link com.ibm.icu.text.Transliterator} is changed. 221 */ 222 /* 223 private void resetTransliterationStart() { 224 start = getSelectionStart(); 225 cursor = start; 226 } 227 */ 228 229 /** 230 * Escape non-ASCII characters as Unicode. 231 * JUST FOR DEBUGGING OUTPUT. 232 */ 233 public static final String escape(String s) { 234 StringBuffer buf = new StringBuffer(); 235 for (int i=0; i<s.length(); ++i) { 236 char c = s.charAt(i); 237 if (c >= ' ' && c <= 0x007F) { 238 if (c == '\\') { 239 buf.append("\\\\"); // That is, "\\" 240 } else { 241 buf.append(c); 242 } 243 } else { 244 buf.append("\\u"); 245 if (c < 0x1000) { 246 buf.append('0'); 247 if (c < 0x100) { 248 buf.append('0'); 249 if (c < 0x10) { 250 buf.append('0'); 251 } 252 } 253 } 254 buf.append(Integer.toHexString(c)); 255 } 256 } 257 return buf.toString(); 258 } 259 } 260