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