Home | History | Annotate | Download | only in translit
      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