1 /*
2  * Copyright (C) 2008-2012  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      */
ComposingText()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      */
debugout()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      */
getStrSegment(int layer, int pos)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      */
toString(int layer, int from, int to)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      */
toString(int layer)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      */
modifyUpper(int layer, int mod_from, int mod_len, int org_len)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      **/
insertStrSegment(int layer, StrSegment str)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      **/
insertStrSegment(int layer1, int layer2, StrSegment str)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      **/
replaceStrSegment0(int layer, StrSegment[] str, int from, int to)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      **/
replaceStrSegment(int layer, StrSegment[] str, int num)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      **/
replaceStrSegment(int layer, StrSegment[] str)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      **/
deleteStrSegment(int layer, int from, int to)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      **/
deleteStrSegment0(int layer, int from, int to, int diff)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      **/
delete(int layer, boolean rightside)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      **/
getStringLayer(int layer)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      */
included(int layer, int pos)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      */
setCursor(int layer, int pos)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      **/
moveCursor(int layer, int diff)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      **/
getCursor(int layer)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      **/
size(int layer)566     public int size(int layer) {
567         return mStringLayer[layer].size();
568     }
569 
570     /**
571      * Clear all information.
572      */
clear()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