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 */ 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