ComposingText.java revision 053d50935e0e311286543bd7c535ae2c863c0de8
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
17package jp.co.omronsoft.openwnn;
18
19import java.util.Iterator;
20import java.util.ArrayList;
21
22import android.util.Log;
23
24/**
25 * The container 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 * LetterConverter and 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 */
34public 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 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</code> 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; 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; 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</code>)
155     * @param org_len  length before modified (# of StrSegments from <code>mod_from</code>)
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 StrSegment at the cursor position.
261     *
262     * @param layer insert to the layer
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 StrSegment at the cursor position(without merging to the previous segment).
274     * <p>
275     * @param layer1 insert to the layer
276     * @param layer2 never merge to the previous segment from <code>layer1</code> to <code>layer2</code>
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   strings 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   strings to replace
332     * @param num   num
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 to replace to
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    private void deleteStrSegment0(int layer, int from, int to, int diff) {
428        ArrayList<StrSegment> strLayer = mStringLayer[layer];
429        if (diff != 0) {
430            for (int i = to + 1; i < strLayer.size(); i++) {
431                StrSegment ss = strLayer.get(i);
432                ss.from -= diff;
433                ss.to   -= diff;
434            }
435        }
436        for (int i = from; i <= to; i++) {
437            strLayer.remove(from);
438        }
439    }
440
441    /**
442     * Delete a segment at the cursor.
443     *
444     * @param layer     layer
445     * @param rightside direction(true:rightside at the cursor, false:leftside at the cursor)
446     **/
447    public int delete(int layer, boolean rightside) {
448        int cursor = mCursor[layer];
449        ArrayList<StrSegment> strLayer = mStringLayer[layer];
450
451        if (!rightside && cursor > 0) {
452            deleteStrSegment(layer, cursor-1, cursor-1);
453            setCursor(layer, cursor - 1);
454        } else if (rightside && cursor < strLayer.size()) {
455            deleteStrSegment(layer, cursor, cursor);
456            setCursor(layer, cursor);
457        }
458        return strLayer.size();
459    }
460
461    /**
462     * Get the string layer.
463     *
464     * @param layer layer
465     *
466     * @return <code>ArrayList</code> of <code>StrSegment</code>; null if error
467     **/
468    public ArrayList getStringLayer(int layer) {
469        try {
470            return mStringLayer[layer];
471        } catch (Exception ex) {
472            return null;
473        }
474    }
475
476    /**
477     * Get upper the segment which includes the position.
478     */
479    private int included(int layer, int pos) {
480        if (pos == 0) {
481            return 0;
482        }
483        int uplayer = layer + 1;
484        int i;
485        ArrayList<StrSegment> strLayer = mStringLayer[uplayer];
486        for (i = 0; i < strLayer.size(); i++) {
487            StrSegment ss = strLayer.get(i);
488            if (ss.from <= pos && pos <= ss.to) {
489                break;
490            }
491        }
492        return i;
493    }
494
495    /**
496     * Set the cursor.
497     *
498     * @param layer layer
499     * @param pos   cursor position
500     *
501     * @return position of cursor
502     */
503    public int setCursor(int layer, int pos) {
504        if (pos > mStringLayer[layer].size()) {
505            pos = mStringLayer[layer].size();
506        }
507        if (pos < 0) {
508            pos = 0;
509        }
510        if (layer == 0) {
511            mCursor[0] = pos;
512            mCursor[1] = included(0, pos);
513            mCursor[2] = included(1, mCursor[1]);
514        } else if (layer == 1) {
515            mCursor[2] = included(1, pos);
516            mCursor[1] = pos;
517            mCursor[0] = (pos > 0)? mStringLayer[1].get(pos - 1).to+1 : 0;
518        } else {
519            mCursor[2] = pos;
520            mCursor[1] = (pos > 0)? mStringLayer[2].get(pos - 1).to+1 : 0;
521            mCursor[0] = (mCursor[1] > 0)? mStringLayer[1].get(mCursor[1] - 1).to+1 : 0;
522        }
523        return pos;
524    }
525
526    /**
527     * Move the cursor.
528     *
529     * @param layer layer
530     * @param diff  relative position from current cursor position
531     *
532     * @return position of cursor
533     **/
534    public int moveCursor(int layer, int diff) {
535        int c = mCursor[layer] + diff;
536
537        return setCursor(layer, c);
538    }
539
540    /**
541     * Get the cursor position.
542     *
543     * @param layer layer
544     * @return cursor position
545     **/
546    public int getCursor(int layer) {
547        return mCursor[layer];
548    }
549
550    /**
551     * Get the number of segments
552     *
553     * @param layer layer
554     * @return number of segments
555     **/
556    public int size(int layer) {
557        return mStringLayer[layer].size();
558    }
559
560    /**
561     * Clear all the information
562     */
563    public void clear() {
564        for (int i = 0; i < MAX_LAYER; i++) {
565            mStringLayer[i].clear();
566            mCursor[i] = 0;
567        }
568    }
569}
570