/* * Copyright (C) 2008-2012 OMRON SOFTWARE Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jp.co.omronsoft.openwnn; import java.util.Iterator; import java.util.ArrayList; import android.util.Log; /** * The container class of composing string. * * This interface is for the class includes information about the * input string, the converted string and its decoration. * {@link LetterConverter} and {@link WnnEngine} get the input string from it, and * store the converted string into it. * * @author Copyright (C) 2009 OMRON SOFTWARE CO., LTD. All Rights Reserved. */ public class ComposingText { /** * Text layer 0. * <br> * This text layer holds key strokes.<br> * (ex) Romaji in Japanese. Parts of Hangul in Korean. */ public static final int LAYER0 = 0; /** * Text layer 1. * <br> * This text layer holds the result of the letter converter.<br> * (ex) Hiragana in Japanese. Pinyin in Chinese. Hangul in Korean. */ public static final int LAYER1 = 1; /** * Text layer 2. * <br> * This text layer holds the result of the consecutive clause converter.<br> * (ex) the result of Kana-to-Kanji conversion in Japanese, * Pinyin-to-Kanji conversion in Chinese, Hangul-to-Hanja conversion in Korean language. */ public static final int LAYER2 = 2; /** Maximum number of layers */ public static final int MAX_LAYER = 3; /** Composing text's layer data */ protected ArrayList<StrSegment>[] mStringLayer; /** Cursor position */ protected int[] mCursor; /** * Constructor */ public ComposingText() { mStringLayer = new ArrayList[MAX_LAYER]; mCursor = new int[MAX_LAYER]; for (int i = 0; i < MAX_LAYER; i++) { mStringLayer[i] = new ArrayList<StrSegment>(); mCursor[i] = 0; } } /** * Output internal information to the log. */ public void debugout() { for (int i = 0; i < MAX_LAYER; i++) { Log.d("OpenWnn", "ComposingText["+i+"]"); Log.d("OpenWnn", " cur = " + mCursor[i]); String tmp = ""; for (Iterator<StrSegment> it = mStringLayer[i].iterator(); it.hasNext();) { StrSegment ss = it.next(); tmp += "(" + ss.string + "," + ss.from + "," + ss.to + ")"; } Log.d("OpenWnn", " str = "+tmp); } } /** * Get a {@link StrSegment} at the position specified. * * @param layer Layer * @param pos Position (<0 : the tail segment) * * @return The segment; {@code null} if error occurs. */ public StrSegment getStrSegment(int layer, int pos) { try { ArrayList<StrSegment> strLayer = mStringLayer[layer]; if (pos < 0) { pos = strLayer.size() - 1; } if (pos >= strLayer.size() || pos < 0) { return null; } return strLayer.get(pos); } catch (Exception ex) { return null; } } /** * Convert the range of segments to a string. * * @param layer Layer * @param from Convert range from * @param to Convert range to * @return The string converted; {@code null} if error occurs. */ public String toString(int layer, int from, int to) { try { StringBuffer buf = new StringBuffer(); ArrayList<StrSegment> strLayer = mStringLayer[layer]; for (int i = from; i <= to; i++) { StrSegment ss = strLayer.get(i); buf.append(ss.string); } return buf.toString(); } catch (Exception ex) { return null; } } /** * Convert segments of the layer to a string. * * @param layer Layer * @return The string converted; {@code null} if error occurs. */ public String toString(int layer) { return this.toString(layer, 0, mStringLayer[layer].size() - 1); } /** * Update the upper layer's data. * * @param layer The base layer * @param mod_from Modified from * @param mod_len Length after modified (# of StrSegments from {@code mod_from}) * @param org_len Length before modified (# of StrSegments from {@code mod_from}) */ private void modifyUpper(int layer, int mod_from, int mod_len, int org_len) { if (layer >= MAX_LAYER - 1) { /* no layer above */ return; } int uplayer = layer + 1; ArrayList<StrSegment> strUplayer = mStringLayer[uplayer]; if (strUplayer.size() <= 0) { /* * if there is no element on above layer, * add a element includes whole elements of the lower layer. */ strUplayer.add(new StrSegment(toString(layer), 0, mStringLayer[layer].size() - 1)); modifyUpper(uplayer, 0, 1, 0); return; } int mod_to = mod_from + ((mod_len == 0)? 0 : (mod_len - 1)); int org_to = mod_from + ((org_len == 0)? 0 : (org_len - 1)); StrSegment last = strUplayer.get(strUplayer.size() - 1); if (last.to < mod_from) { /* add at the tail */ last.to = mod_to; last.string = toString(layer, last.from, last.to); modifyUpper(uplayer, strUplayer.size()-1, 1, 1); return; } int uplayer_mod_from = -1; int uplayer_org_to = -1; for (int i = 0; i < strUplayer.size(); i++) { StrSegment ss = strUplayer.get(i); if (ss.from > mod_from) { if (ss.to <= org_to) { /* the segment is included */ if (uplayer_mod_from < 0) { uplayer_mod_from = i; } uplayer_org_to = i; } else { /* included in this segment */ uplayer_org_to = i; break; } } else { if (org_len == 0 && ss.from == mod_from) { /* when an element is added */ uplayer_mod_from = i - 1; uplayer_org_to = i - 1; break; } else { /* start from this segment */ uplayer_mod_from = i; uplayer_org_to = i; if (ss.to >= org_to) { break; } } } } int diff = mod_len - org_len; if (uplayer_mod_from >= 0) { /* update an element */ StrSegment ss = strUplayer.get(uplayer_mod_from); int last_to = ss.to; int next = uplayer_mod_from + 1; for (int i = next; i <= uplayer_org_to; i++) { ss = strUplayer.get(next); if (last_to > ss.to) { last_to = ss.to; } strUplayer.remove(next); } ss.to = (last_to < mod_to)? mod_to : (last_to + diff); ss.string = toString(layer, ss.from, ss.to); for (int i = next; i < strUplayer.size(); i++) { ss = strUplayer.get(i); ss.from += diff; ss.to += diff; } modifyUpper(uplayer, uplayer_mod_from, 1, uplayer_org_to - uplayer_mod_from + 1); } else { /* add an element at the head */ StrSegment ss = new StrSegment(toString(layer, mod_from, mod_to), mod_from, mod_to); strUplayer.add(0, ss); for (int i = 1; i < strUplayer.size(); i++) { ss = strUplayer.get(i); ss.from += diff; ss.to += diff; } modifyUpper(uplayer, 0, 1, 0); } return; } /** * Insert a {@link StrSegment} at the cursor position. * * @param layer Layer to insert * @param str String **/ public void insertStrSegment(int layer, StrSegment str) { int cursor = mCursor[layer]; mStringLayer[layer].add(cursor, str); modifyUpper(layer, cursor, 1, 0); setCursor(layer, cursor + 1); } /** * Insert a {@link StrSegment} at the cursor position(without merging to the previous segment). * <p> * @param layer1 Layer to insert * @param layer2 Never merge to the previous segment from {@code layer1} to {@code layer2}. * @param str String **/ public void insertStrSegment(int layer1, int layer2, StrSegment str) { mStringLayer[layer1].add(mCursor[layer1], str); mCursor[layer1]++; for (int i = layer1 + 1; i <= layer2; i++) { int pos = mCursor[i-1] - 1; StrSegment tmp = new StrSegment(str.string, pos, pos); ArrayList<StrSegment> strLayer = mStringLayer[i]; strLayer.add(mCursor[i], tmp); mCursor[i]++; for (int j = mCursor[i]; j < strLayer.size(); j++) { StrSegment ss = strLayer.get(j); ss.from++; ss.to++; } } int cursor = mCursor[layer2]; modifyUpper(layer2, cursor - 1, 1, 0); setCursor(layer2, cursor); } /** * Replace segments at the range specified. * * @param layer Layer * @param str String segment array to replace * @param from Replace from * @param to Replace to **/ protected void replaceStrSegment0(int layer, StrSegment[] str, int from, int to) { ArrayList<StrSegment> strLayer = mStringLayer[layer]; if (from < 0 || from > strLayer.size()) { from = strLayer.size(); } if (to < 0 || to > strLayer.size()) { to = strLayer.size(); } for (int i = from; i <= to; i++) { strLayer.remove(from); } for (int i = str.length - 1; i >= 0; i--) { strLayer.add(from, str[i]); } modifyUpper(layer, from, str.length, to - from + 1); } /** * Replace segments at the range specified. * * @param layer Layer * @param str String segment array to replace * @param num Size of string segment array **/ public void replaceStrSegment(int layer, StrSegment[] str, int num) { int cursor = mCursor[layer]; replaceStrSegment0(layer, str, cursor - num, cursor - 1); setCursor(layer, cursor + str.length - num); } /** * Replace the segment at the cursor. * * @param layer Layer * @param str String segment to replace **/ public void replaceStrSegment(int layer, StrSegment[] str) { int cursor = mCursor[layer]; replaceStrSegment0(layer, str, cursor - 1, cursor - 1); setCursor(layer, cursor + str.length - 1); } /** * Delete segments. * * @param layer Layer * @param from Delete from * @param to Delete to **/ public void deleteStrSegment(int layer, int from, int to) { int[] fromL = new int[] {-1, -1, -1}; int[] toL = new int[] {-1, -1, -1}; ArrayList<StrSegment> strLayer2 = mStringLayer[2]; ArrayList<StrSegment> strLayer1 = mStringLayer[1]; if (layer == 2) { fromL[2] = from; toL[2] = to; fromL[1] = strLayer2.get(from).from; toL[1] = strLayer2.get(to).to; fromL[0] = strLayer1.get(fromL[1]).from; toL[0] = strLayer1.get(toL[1]).to; } else if (layer == 1) { fromL[1] = from; toL[1] = to; fromL[0] = strLayer1.get(from).from; toL[0] = strLayer1.get(to).to; } else { fromL[0] = from; toL[0] = to; } int diff = to - from + 1; for (int lv = 0; lv < MAX_LAYER; lv++) { if (fromL[lv] >= 0) { deleteStrSegment0(lv, fromL[lv], toL[lv], diff); } else { int boundary_from = -1; int boundary_to = -1; ArrayList<StrSegment> strLayer = mStringLayer[lv]; for (int i = 0; i < strLayer.size(); i++) { StrSegment ss = (StrSegment)strLayer.get(i); if ((ss.from >= fromL[lv-1] && ss.from <= toL[lv-1]) || (ss.to >= fromL[lv-1] && ss.to <= toL[lv-1]) ) { if (fromL[lv] < 0) { fromL[lv] = i; boundary_from = ss.from; } toL[lv] = i; boundary_to = ss.to; } else if (ss.from <= fromL[lv-1] && ss.to >= toL[lv-1]) { boundary_from = ss.from; boundary_to = ss.to; fromL[lv] = i; toL[lv] = i; break; } else if (ss.from > toL[lv-1]) { break; } } if (boundary_from != fromL[lv-1] || boundary_to != toL[lv-1]) { deleteStrSegment0(lv, fromL[lv] + 1, toL[lv], diff); boundary_to -= diff; StrSegment[] tmp = new StrSegment[] { (new StrSegment(toString(lv-1), boundary_from, boundary_to)) }; replaceStrSegment0(lv, tmp, fromL[lv], fromL[lv]); return; } else { deleteStrSegment0(lv, fromL[lv], toL[lv], diff); } } diff = toL[lv] - fromL[lv] + 1; } } /** * Delete segments (internal method). * * @param layer Layer * @param from Delete from * @param to Delete to * @param diff Differential **/ private void deleteStrSegment0(int layer, int from, int to, int diff) { ArrayList<StrSegment> strLayer = mStringLayer[layer]; if (diff != 0) { for (int i = to + 1; i < strLayer.size(); i++) { StrSegment ss = strLayer.get(i); ss.from -= diff; ss.to -= diff; } } for (int i = from; i <= to; i++) { strLayer.remove(from); } } /** * Delete a segment at the cursor. * * @param layer Layer * @param rightside {@code true} if direction is rightward at the cursor, {@code false} if direction is leftward at the cursor * @return The number of string segments in the specified layer **/ public int delete(int layer, boolean rightside) { int cursor = mCursor[layer]; ArrayList<StrSegment> strLayer = mStringLayer[layer]; if (!rightside && cursor > 0) { deleteStrSegment(layer, cursor-1, cursor-1); setCursor(layer, cursor - 1); } else if (rightside && cursor < strLayer.size()) { deleteStrSegment(layer, cursor, cursor); setCursor(layer, cursor); } return strLayer.size(); } /** * Get the string layer. * * @param layer Layer * @return {@link ArrayList} of {@link StrSegment}; {@code null} if error. **/ public ArrayList<StrSegment> getStringLayer(int layer) { try { return mStringLayer[layer]; } catch (Exception ex) { return null; } } /** * Get upper the segment which includes the position. * * @param layer Layer * @param pos Position * @return Index of upper segment */ private int included(int layer, int pos) { if (pos == 0) { return 0; } int uplayer = layer + 1; int i; ArrayList<StrSegment> strLayer = mStringLayer[uplayer]; for (i = 0; i < strLayer.size(); i++) { StrSegment ss = strLayer.get(i); if (ss.from <= pos && pos <= ss.to) { break; } } return i; } /** * Set the cursor. * * @param layer Layer * @param pos Position of cursor * @return New position of cursor */ public int setCursor(int layer, int pos) { if (pos > mStringLayer[layer].size()) { pos = mStringLayer[layer].size(); } if (pos < 0) { pos = 0; } if (layer == 0) { mCursor[0] = pos; mCursor[1] = included(0, pos); mCursor[2] = included(1, mCursor[1]); } else if (layer == 1) { mCursor[2] = included(1, pos); mCursor[1] = pos; mCursor[0] = (pos > 0)? mStringLayer[1].get(pos - 1).to+1 : 0; } else { mCursor[2] = pos; mCursor[1] = (pos > 0)? mStringLayer[2].get(pos - 1).to+1 : 0; mCursor[0] = (mCursor[1] > 0)? mStringLayer[1].get(mCursor[1] - 1).to+1 : 0; } return pos; } /** * Move the cursor. * * @param layer Layer * @param diff Relative position from current cursor position * @return New position of cursor **/ public int moveCursor(int layer, int diff) { int c = mCursor[layer] + diff; return setCursor(layer, c); } /** * Get the cursor position. * * @param layer Layer * @return cursor Current position of cursor **/ public int getCursor(int layer) { return mCursor[layer]; } /** * Get the number of segments. * * @param layer Layer * @return Number of segments **/ public int size(int layer) { return mStringLayer[layer].size(); } /** * Clear all information. */ public void clear() { for (int i = 0; i < MAX_LAYER; i++) { mStringLayer[i].clear(); mCursor[i] = 0; } } }