Home | History | Annotate | Download | only in openwnn
      1 /*
      2  * Copyright (C) 2008,2009  OMRON SOFTWARE Co., Ltd.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package jp.co.omronsoft.openwnn;
     18 
     19 import java.util.Iterator;
     20 import java.util.ArrayList;
     21 
     22 import android.util.Log;
     23 
     24 /**
     25  * The container class of composing string.
     26  *
     27  * This interface is for the class includes information about the
     28  * input string, the converted string and its decoration.
     29  * {@link LetterConverter} and {@link WnnEngine} get the input string from it, and
     30  * store the converted string into it.
     31  *
     32  * @author Copyright (C) 2009 OMRON SOFTWARE CO., LTD.  All Rights Reserved.
     33  */
     34 public class ComposingText {
     35     /**
     36      * Text layer 0.
     37      * <br>
     38      * This text layer holds key strokes.<br>
     39      * (ex) Romaji in Japanese.  Parts of Hangul in Korean.
     40      */
     41     public static final int LAYER0  = 0;
     42     /**
     43      * Text layer 1.
     44      * <br>
     45      * This text layer holds the result of the letter converter.<br>
     46      * (ex) Hiragana in Japanese. Pinyin in Chinese. Hangul in Korean.
     47      */
     48     public static final int LAYER1  = 1;
     49     /**
     50      * Text layer 2.
     51      * <br>
     52      * This text layer holds the result of the consecutive clause converter.<br>
     53      * (ex) the result of Kana-to-Kanji conversion in Japanese,
     54      *      Pinyin-to-Kanji conversion in Chinese, Hangul-to-Hanja conversion in Korean language.
     55      */
     56     public static final int LAYER2  = 2;
     57     /** Maximum number of layers */
     58     public static final int MAX_LAYER = 3;
     59 
     60     /** Composing text's layer data */
     61     protected ArrayList<StrSegment>[] mStringLayer;
     62     /** Cursor position */
     63     protected int[] mCursor;
     64 
     65     /**
     66      * Constructor
     67      */
     68     public ComposingText() {
     69         mStringLayer = new ArrayList[MAX_LAYER];
     70         mCursor = new int[MAX_LAYER];
     71         for (int i = 0; i < MAX_LAYER; i++) {
     72             mStringLayer[i] = new ArrayList<StrSegment>();
     73             mCursor[i] = 0;
     74         }
     75     }
     76 
     77     /**
     78      * Output internal information to the log.
     79      */
     80     public void debugout() {
     81         for (int i = 0; i < MAX_LAYER; i++) {
     82             Log.d("OpenWnn", "ComposingText["+i+"]");
     83             Log.d("OpenWnn", "  cur = " + mCursor[i]);
     84             String tmp = "";
     85             for (Iterator<StrSegment> it = mStringLayer[i].iterator(); it.hasNext();) {
     86                 StrSegment ss = it.next();
     87                 tmp += "(" + ss.string + "," + ss.from + "," + ss.to + ")";
     88             }
     89             Log.d("OpenWnn", "  str = "+tmp);
     90         }
     91     }
     92 
     93     /**
     94      * Get a {@link StrSegment} at the position specified.
     95      *
     96      * @param layer     Layer
     97      * @param pos       Position (<0 : the tail segment)
     98      *
     99      * @return          The segment; {@code null} if error occurs.
    100      */
    101     public StrSegment getStrSegment(int layer, int pos) {
    102         try {
    103             ArrayList<StrSegment> strLayer = mStringLayer[layer];
    104             if (pos < 0) {
    105                 pos = strLayer.size() - 1;
    106             }
    107             if (pos >= strLayer.size() || pos < 0) {
    108                 return null;
    109             }
    110             return strLayer.get(pos);
    111         } catch (Exception ex) {
    112             return null;
    113         }
    114     }
    115 
    116     /**
    117      * Convert the range of segments to a string.
    118      *
    119      * @param layer     Layer
    120      * @param from      Convert range from
    121      * @param to        Convert range to
    122      * @return          The string converted; {@code null} if error occurs.
    123      */
    124     public String toString(int layer, int from, int to) {
    125         try {
    126             StringBuffer buf = new StringBuffer();
    127             ArrayList<StrSegment> strLayer = mStringLayer[layer];
    128 
    129             for (int i = from; i <= to; i++) {
    130                 StrSegment ss = strLayer.get(i);
    131                 buf.append(ss.string);
    132             }
    133             return buf.toString();
    134         } catch (Exception ex) {
    135             return null;
    136         }
    137     }
    138 
    139     /**
    140      * Convert segments of the layer to a string.
    141      *
    142      * @param layer     Layer
    143      * @return          The string converted; {@code null} if error occurs.
    144      */
    145     public String toString(int layer) {
    146         return this.toString(layer, 0, mStringLayer[layer].size() - 1);
    147     }
    148 
    149     /**
    150      * Update the upper layer's data.
    151      *
    152      * @param layer         The base layer
    153      * @param mod_from      Modified from
    154      * @param mod_len       Length after modified (# of StrSegments from {@code mod_from})
    155      * @param org_len       Length before modified (# of StrSegments from {@code mod_from})
    156      */
    157     private void modifyUpper(int layer, int mod_from, int mod_len, int org_len) {
    158         if (layer >= MAX_LAYER - 1) {
    159             /* no layer above */
    160             return;
    161         }
    162 
    163         int uplayer = layer + 1;
    164         ArrayList<StrSegment> strUplayer = mStringLayer[uplayer];
    165         if (strUplayer.size() <= 0) {
    166             /*
    167              * if there is no element on above layer,
    168              * add a element includes whole elements of the lower layer.
    169              */
    170             strUplayer.add(new StrSegment(toString(layer), 0, mStringLayer[layer].size() - 1));
    171             modifyUpper(uplayer, 0, 1, 0);
    172             return;
    173         }
    174 
    175         int mod_to = mod_from + ((mod_len == 0)? 0 : (mod_len - 1));
    176         int org_to = mod_from + ((org_len == 0)? 0 : (org_len - 1));
    177         StrSegment last = strUplayer.get(strUplayer.size() - 1);
    178         if (last.to < mod_from) {
    179             /* add at the tail */
    180             last.to = mod_to;
    181             last.string = toString(layer, last.from, last.to);
    182             modifyUpper(uplayer, strUplayer.size()-1, 1, 1);
    183             return;
    184         }
    185 
    186         int uplayer_mod_from = -1;
    187         int uplayer_org_to = -1;
    188         for (int i = 0; i < strUplayer.size(); i++) {
    189             StrSegment ss = strUplayer.get(i);
    190             if (ss.from > mod_from) {
    191                 if (ss.to <= org_to) {
    192                     /* the segment is included */
    193                     if (uplayer_mod_from < 0) {
    194                         uplayer_mod_from = i;
    195                     }
    196                     uplayer_org_to = i;
    197                 } else {
    198                     /* included in this segment */
    199                     uplayer_org_to = i;
    200                     break;
    201                 }
    202             } else {
    203                 if (org_len == 0 && ss.from == mod_from) {
    204                     /* when an element is added */
    205                     uplayer_mod_from = i - 1;
    206                     uplayer_org_to   = i - 1;
    207                     break;
    208                 } else {
    209                     /* start from this segment */
    210                     uplayer_mod_from = i;
    211                     uplayer_org_to = i;
    212                     if (ss.to >= org_to) {
    213                         break;
    214                     }
    215                 }
    216             }
    217         }
    218 
    219         int diff = mod_len - org_len;
    220         if (uplayer_mod_from >= 0) {
    221             /* update an element */
    222             StrSegment ss = strUplayer.get(uplayer_mod_from);
    223             int last_to = ss.to;
    224             int next = uplayer_mod_from + 1;
    225             for (int i = next; i <= uplayer_org_to; i++) {
    226                 ss = strUplayer.get(next);
    227                 if (last_to > ss.to) {
    228                     last_to = ss.to;
    229                 }
    230                 strUplayer.remove(next);
    231             }
    232             ss.to = (last_to < mod_to)? mod_to : (last_to + diff);
    233 
    234             ss.string = toString(layer, ss.from, ss.to);
    235 
    236             for (int i = next; i < strUplayer.size(); i++) {
    237                 ss = strUplayer.get(i);
    238                 ss.from += diff;
    239                 ss.to   += diff;
    240             }
    241 
    242             modifyUpper(uplayer, uplayer_mod_from, 1, uplayer_org_to - uplayer_mod_from + 1);
    243         } else {
    244             /* add an element at the head */
    245             StrSegment ss = new StrSegment(toString(layer, mod_from, mod_to),
    246                                            mod_from, mod_to);
    247             strUplayer.add(0, ss);
    248             for (int i = 1; i < strUplayer.size(); i++) {
    249                 ss = strUplayer.get(i);
    250                 ss.from += diff;
    251                 ss.to   += diff;
    252             }
    253             modifyUpper(uplayer, 0, 1, 0);
    254         }
    255 
    256         return;
    257     }
    258 
    259     /**
    260      * Insert a {@link StrSegment} at the cursor position.
    261      *
    262      * @param layer Layer to insert
    263      * @param str   String
    264      **/
    265     public void insertStrSegment(int layer, StrSegment str) {
    266         int cursor = mCursor[layer];
    267         mStringLayer[layer].add(cursor, str);
    268         modifyUpper(layer, cursor, 1, 0);
    269         setCursor(layer, cursor + 1);
    270     }
    271 
    272     /**
    273      * Insert a {@link StrSegment} at the cursor position(without merging to the previous segment).
    274      * <p>
    275      * @param layer1        Layer to insert
    276      * @param layer2        Never merge to the previous segment from {@code layer1} to {@code layer2}.
    277      * @param str           String
    278      **/
    279     public void insertStrSegment(int layer1, int layer2, StrSegment str) {
    280         mStringLayer[layer1].add(mCursor[layer1], str);
    281         mCursor[layer1]++;
    282 
    283         for (int i = layer1 + 1; i <= layer2; i++) {
    284             int pos = mCursor[i-1] - 1;
    285             StrSegment tmp = new StrSegment(str.string, pos, pos);
    286             ArrayList<StrSegment> strLayer = mStringLayer[i];
    287             strLayer.add(mCursor[i], tmp);
    288             mCursor[i]++;
    289             for (int j = mCursor[i]; j < strLayer.size(); j++) {
    290                 StrSegment ss = strLayer.get(j);
    291                 ss.from++;
    292                 ss.to++;
    293             }
    294         }
    295         int cursor = mCursor[layer2];
    296         modifyUpper(layer2, cursor - 1, 1, 0);
    297         setCursor(layer2, cursor);
    298     }
    299 
    300     /**
    301      * Replace segments at the range specified.
    302      *
    303      * @param layer     Layer
    304      * @param str       String segment array to replace
    305      * @param from      Replace from
    306      * @param to        Replace to
    307      **/
    308     protected void replaceStrSegment0(int layer, StrSegment[] str, int from, int to) {
    309         ArrayList<StrSegment> strLayer = mStringLayer[layer];
    310 
    311         if (from < 0 || from > strLayer.size()) {
    312             from = strLayer.size();
    313         }
    314         if (to < 0 || to > strLayer.size()) {
    315             to = strLayer.size();
    316         }
    317         for (int i = from; i <= to; i++) {
    318             strLayer.remove(from);
    319         }
    320         for (int i = str.length - 1; i >= 0; i--) {
    321             strLayer.add(from, str[i]);
    322         }
    323 
    324         modifyUpper(layer, from, str.length, to - from + 1);
    325     }
    326 
    327     /**
    328      * Replace segments at the range specified.
    329      *
    330      * @param layer     Layer
    331      * @param str       String segment array to replace
    332      * @param num       Size of string segment array
    333      **/
    334     public void replaceStrSegment(int layer, StrSegment[] str, int num) {
    335         int cursor = mCursor[layer];
    336         replaceStrSegment0(layer, str, cursor - num, cursor - 1);
    337         setCursor(layer, cursor + str.length - num);
    338     }
    339 
    340     /**
    341      * Replace the segment at the cursor.
    342      *
    343      * @param layer     Layer
    344      * @param str       String segment to replace
    345      **/
    346     public void replaceStrSegment(int layer, StrSegment[] str) {
    347         int cursor = mCursor[layer];
    348         replaceStrSegment0(layer, str, cursor - 1, cursor - 1);
    349         setCursor(layer, cursor + str.length - 1);
    350     }
    351 
    352     /**
    353      * Delete segments.
    354      *
    355      * @param layer Layer
    356      * @param from  Delete from
    357      * @param to    Delete to
    358      **/
    359     public void deleteStrSegment(int layer, int from, int to) {
    360         int[] fromL = new int[] {-1, -1, -1};
    361         int[] toL   = new int[] {-1, -1, -1};
    362 
    363         ArrayList<StrSegment> strLayer2 = mStringLayer[2];
    364         ArrayList<StrSegment> strLayer1 = mStringLayer[1];
    365 
    366         if (layer == 2) {
    367             fromL[2] = from;
    368             toL[2]   = to;
    369             fromL[1] = strLayer2.get(from).from;
    370             toL[1]   = strLayer2.get(to).to;
    371             fromL[0] = strLayer1.get(fromL[1]).from;
    372             toL[0]   = strLayer1.get(toL[1]).to;
    373         } else if (layer == 1) {
    374             fromL[1] = from;
    375             toL[1]   = to;
    376             fromL[0] = strLayer1.get(from).from;
    377             toL[0]   = strLayer1.get(to).to;
    378         } else {
    379             fromL[0] = from;
    380             toL[0]   = to;
    381         }
    382 
    383         int diff = to - from + 1;
    384         for (int lv = 0; lv < MAX_LAYER; lv++) {
    385             if (fromL[lv] >= 0) {
    386                 deleteStrSegment0(lv, fromL[lv], toL[lv], diff);
    387             } else {
    388                 int boundary_from = -1;
    389                 int boundary_to   = -1;
    390                 ArrayList<StrSegment> strLayer = mStringLayer[lv];
    391                 for (int i = 0; i < strLayer.size(); i++) {
    392                     StrSegment ss = (StrSegment)strLayer.get(i);
    393                     if ((ss.from >= fromL[lv-1] && ss.from <= toL[lv-1]) ||
    394                         (ss.to >= fromL[lv-1] && ss.to <= toL[lv-1]) ) {
    395                         if (fromL[lv] < 0) {
    396                             fromL[lv] = i;
    397                             boundary_from = ss.from;
    398                         }
    399                         toL[lv] = i;
    400                         boundary_to = ss.to;
    401                     } else if (ss.from <= fromL[lv-1] && ss.to >= toL[lv-1]) {
    402                         boundary_from = ss.from;
    403                         boundary_to   = ss.to;
    404                         fromL[lv] = i;
    405                         toL[lv] = i;
    406                         break;
    407                     } else if (ss.from > toL[lv-1]) {
    408                         break;
    409                     }
    410                 }
    411                 if (boundary_from != fromL[lv-1] || boundary_to != toL[lv-1]) {
    412                     deleteStrSegment0(lv, fromL[lv] + 1, toL[lv], diff);
    413                     boundary_to -= diff;
    414                     StrSegment[] tmp = new StrSegment[] {
    415                         (new StrSegment(toString(lv-1), boundary_from, boundary_to))
    416                     };
    417                     replaceStrSegment0(lv, tmp, fromL[lv], fromL[lv]);
    418                     return;
    419                 } else {
    420                     deleteStrSegment0(lv, fromL[lv], toL[lv], diff);
    421                 }
    422             }
    423             diff = toL[lv] - fromL[lv] + 1;
    424         }
    425     }
    426 
    427     /**
    428      * Delete segments (internal method).
    429      *
    430      * @param layer     Layer
    431      * @param from      Delete from
    432      * @param to        Delete to
    433      * @param diff      Differential
    434      **/
    435     private void deleteStrSegment0(int layer, int from, int to, int diff) {
    436         ArrayList<StrSegment> strLayer = mStringLayer[layer];
    437         if (diff != 0) {
    438             for (int i = to + 1; i < strLayer.size(); i++) {
    439                 StrSegment ss = strLayer.get(i);
    440                 ss.from -= diff;
    441                 ss.to   -= diff;
    442             }
    443         }
    444         for (int i = from; i <= to; i++) {
    445             strLayer.remove(from);
    446         }
    447     }
    448 
    449     /**
    450      * Delete a segment at the cursor.
    451      *
    452      * @param layer         Layer
    453      * @param rightside     {@code true} if direction is rightward at the cursor, {@code false} if direction is leftward at the cursor
    454      * @return              The number of string segments in the specified layer
    455      **/
    456     public int delete(int layer, boolean rightside) {
    457         int cursor = mCursor[layer];
    458         ArrayList<StrSegment> strLayer = mStringLayer[layer];
    459 
    460         if (!rightside && cursor > 0) {
    461             deleteStrSegment(layer, cursor-1, cursor-1);
    462             setCursor(layer, cursor - 1);
    463         } else if (rightside && cursor < strLayer.size()) {
    464             deleteStrSegment(layer, cursor, cursor);
    465             setCursor(layer, cursor);
    466         }
    467         return strLayer.size();
    468     }
    469 
    470     /**
    471      * Get the string layer.
    472      *
    473      * @param layer     Layer
    474      * @return          {@link ArrayList} of {@link StrSegment}; {@code null} if error.
    475      **/
    476     public ArrayList<StrSegment> getStringLayer(int layer) {
    477         try {
    478             return mStringLayer[layer];
    479         } catch (Exception ex) {
    480             return null;
    481         }
    482     }
    483 
    484     /**
    485      * Get upper the segment which includes the position.
    486      *
    487      * @param layer     Layer
    488      * @param pos       Position
    489      * @return      Index of upper segment
    490      */
    491     private int included(int layer, int pos) {
    492         if (pos == 0) {
    493             return 0;
    494         }
    495         int uplayer = layer + 1;
    496         int i;
    497         ArrayList<StrSegment> strLayer = mStringLayer[uplayer];
    498         for (i = 0; i < strLayer.size(); i++) {
    499             StrSegment ss = strLayer.get(i);
    500             if (ss.from <= pos && pos <= ss.to) {
    501                 break;
    502             }
    503         }
    504         return i;
    505     }
    506 
    507     /**
    508      * Set the cursor.
    509      *
    510      * @param layer     Layer
    511      * @param pos       Position of cursor
    512      * @return      New position of cursor
    513      */
    514     public int setCursor(int layer, int pos) {
    515         if (pos > mStringLayer[layer].size()) {
    516             pos = mStringLayer[layer].size();
    517         }
    518         if (pos < 0) {
    519             pos = 0;
    520         }
    521         if (layer == 0) {
    522             mCursor[0] = pos;
    523             mCursor[1] = included(0, pos);
    524             mCursor[2] = included(1, mCursor[1]);
    525         } else if (layer == 1) {
    526             mCursor[2] = included(1, pos);
    527             mCursor[1] = pos;
    528             mCursor[0] = (pos > 0)? mStringLayer[1].get(pos - 1).to+1 : 0;
    529         } else {
    530             mCursor[2] = pos;
    531             mCursor[1] = (pos > 0)? mStringLayer[2].get(pos - 1).to+1 : 0;
    532             mCursor[0] = (mCursor[1] > 0)? mStringLayer[1].get(mCursor[1] - 1).to+1 : 0;
    533         }
    534         return pos;
    535     }
    536 
    537     /**
    538      * Move the cursor.
    539      *
    540      * @param layer     Layer
    541      * @param diff      Relative position from current cursor position
    542      * @return      New position of cursor
    543      **/
    544     public int moveCursor(int layer, int diff) {
    545         int c = mCursor[layer] + diff;
    546 
    547         return setCursor(layer, c);
    548     }
    549 
    550     /**
    551      * Get the cursor position.
    552      *
    553      * @param layer     Layer
    554      * @return cursor   Current position of cursor
    555      **/
    556     public int getCursor(int layer) {
    557         return mCursor[layer];
    558     }
    559 
    560     /**
    561      * Get the number of segments.
    562      *
    563      * @param layer     Layer
    564      * @return          Number of segments
    565      **/
    566     public int size(int layer) {
    567         return mStringLayer[layer].size();
    568     }
    569 
    570     /**
    571      * Clear all information.
    572      */
    573     public void clear() {
    574         for (int i = 0; i < MAX_LAYER; i++) {
    575             mStringLayer[i].clear();
    576             mCursor[i] = 0;
    577         }
    578     }
    579 }
    580