blob: 83bec26c6100430f7e7e0e7f4b0d330ec29c894f [file] [log] [blame]
/*
* Copyright (C) 2008,2009 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.ArrayList;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.media.MediaPlayer;
import android.os.Vibrator;
import android.text.Layout;
import android.text.Styled;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.View.OnTouchListener;
import android.view.ViewGroup.LayoutParams;
import android.view.GestureDetector;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.EditText;
import android.text.TextPaint;
/**
* The default candidates view manager class using {@link EditText}.
*
* @author Copyright (C) 2009 OMRON SOFTWARE CO., LTD. All Rights Reserved.
*/
public class TextCandidatesViewManager implements CandidatesViewManager, OnTouchListener,
GestureDetector.OnGestureListener {
/** Height of a line */
public static final int LINE_HEIGHT = 48;
/** Number of lines to display (Portrait) */
public static final int LINE_NUM_PORTRAIT = 2;
/** Number of lines to full-display (Portrait) */
public static final int LINE_NUM_PORTRAIT_FULL = 5;
/** Number of lines to display (Landscape) */
public static final int LINE_NUM_LANDSCAPE = 1;
/** Number of lines to full-display (Landscape) */
public static final int LINE_NUM_LANDSCAPE_FULL = 3;
/** Separator */
public static final String CANDIDATE_SEPARATOR = "\u3000 ";
/** Maximum lines */
private static final int DISPLAY_LINE_MAX_COUNT = 1000;
/** Adjusted value for detecting the selected candidate */
private static final int TOUCH_ADJUSTED_VALUE = 1;
/** Body view of the candidates list */
private ViewGroup mViewBody;
/** Scroller of {@code mViewBodyText} */
private ScrollView mViewBodyScroll;
/** Body of the list view */
private EditText mViewBodyText;
/** Text displayed bottom of the view when there are more candidates. */
private TextView mReadMoreText;
/** {@link OpenWnn} instance using this manager */
private OpenWnn mWnn;
/** View type (VIEW_TYPE_NORMAL or VIEW_TYPE_FULL or VIEW_TYPE_CLOSE) */
private int mViewType;
/** Portrait display({@code true}) or landscape({@code false}) */
private boolean mPortrait;
/** Width of the view */
private int mViewWidth;
/** Height of the view */
private int mViewHeight;
/** Whether hide the view if there is no candidates */
private boolean mAutoHideMode;
/** The converter to be get candidates from and notice the selected candidate to. */
private WnnEngine mConverter;
/** Limitation of displaying candidates */
private int mDisplayLimit;
/** The last displaying word */
private WnnWord mLastWord;
/** Vibrator for touch vibration */
private Vibrator mVibrator = null;
/** MediaPlayer for click sound */
private MediaPlayer mSound = null;
/** Number of candidates displaying */
private int mWordCount;
private int mWordCountInNormalView;
/** List of word's index to convert from the position of the cursor */
private ArrayList<Integer> mPositionToWordIndexArray;
/** The string to display candidates */
private StringBuffer mCandidates;
/** List of the start position of each candidate */
private ArrayList<Integer> mStartPositionArray;
/** List of the end position of each candidate */
private ArrayList<Integer> mEndPositionArray;
/** List of candidates */
private ArrayList<WnnWord> mWnnWordArray;
/** Gesture detector */
private GestureDetector mGestureDetector;
/** The word pressed */
private WnnWord mWord;
/** Text on the select button */
private String mSelectBottonText = null;
/** Text on the cancel button */
private String mCancelBottonText = null;
/** Character width of the candidate area */
private int mLineLength = 0;
/** Word count on a single line in the candidate area */
private int mLineWordCount = -1;
/** {@code true} if the hardware keyboard is shown */
private boolean mHardKeyboardHidden = true;
/** {@code true} if the candidate delete state is selected */
private boolean mCandidateDeleteState = false;
/** {@code true} if the full screen mode is selected */
private boolean mIsFullView = false;
/** {@code true} if the selection state is started */
private boolean mHasStartedSelect = false;
/** {@code true} if the candidate list is created */
private boolean mHasCreatedCandidateList = false;
/** The event object for "touch" */
private MotionEvent mMotionEvent = null;
/** The offset when the candidates is flowed out the candidate window */
private int mDisplayEndOffset = 0;
/** {@code true} if there are more candidates to display. */
private boolean mCanReadMore = false;
/**
* Constructor
*/
public TextCandidatesViewManager() {
this(-1);
}
/**
* Constructor
*
* @param displayLimit The limit of display
*/
public TextCandidatesViewManager(int displayLimit) {
this.mDisplayLimit = displayLimit;
this.mCandidates = new StringBuffer();
this.mStartPositionArray = new ArrayList<Integer>();
this.mEndPositionArray = new ArrayList<Integer>();
this.mPositionToWordIndexArray = new ArrayList<Integer>();
this.mWnnWordArray = new ArrayList<WnnWord>();
this.mAutoHideMode = true;
}
/**
* Set auto-hide mode.
* @param hide {@code true} if the view will hidden when no candidate exists;
* {@code false} if the view is always shown.
*/
public void setAutoHide(boolean hide) {
mAutoHideMode = hide;
}
/** @see CandidatesViewManager */
public View initView(OpenWnn parent, int width, int height) {
mWnn = parent;
mViewWidth = width;
mSelectBottonText = mWnn.getResources().getString(R.string.button_candidate_select);
mCancelBottonText = mWnn.getResources().getString(R.string.button_candidate_cancel);
mViewBody = (ViewGroup)parent.getLayoutInflater().inflate(R.layout.candidates, null);
mViewBodyScroll = (ScrollView)mViewBody.findViewById(R.id.candview_scroll);
mViewBodyScroll.setOnTouchListener(this);
mViewBodyText = (EditText)mViewBody.findViewById(R.id.text_candidates_view);
mViewBodyText.setOnTouchListener(this);
mViewBodyText.setTextSize(18.0f);
mViewBodyText.setLineSpacing(6.0f, 1.5f);
mViewBodyText.setIncludeFontPadding(false);
mViewBodyText.setFocusable(true);
mViewBodyText.setCursorVisible(false);
mViewBodyText.setGravity(Gravity.TOP);
mReadMoreText = (TextView)mViewBody.findViewById(R.id.read_more_text);
mReadMoreText.setText(mWnn.getResources().getString(R.string.read_more));
mReadMoreText.setTextSize(24.0f);
mPortrait = (height > 450)? true : false;
setViewType(CandidatesViewManager.VIEW_TYPE_CLOSE);
mGestureDetector = new GestureDetector(this);
return mViewBody;
}
/** @see CandidatesViewManager#getCurrentView */
public View getCurrentView() {
return mViewBody;
}
/** @see CandidatesViewManager#setViewType */
public void setViewType(int type) {
boolean readMore = setViewLayout(type);
addNewlineIfNecessary();
if (readMore) {
displayCandidates(this.mConverter, false, -1);
} else {
if (type == CandidatesViewManager.VIEW_TYPE_NORMAL) {
mIsFullView = false;
if (mDisplayEndOffset > 0) {
int maxLine = getMaxLine();
displayCandidates(this.mConverter, false, maxLine);
} else {
setReadMore();
}
} else {
if (mViewBody.isShown()) {
mWnn.setCandidatesViewShown(false);
}
}
}
}
/**
* Set the view layout
*
* @param type View type
* @return {@code true} if display is updated; {@code false} if otherwise
*/
private boolean setViewLayout(int type) {
mViewType = type;
boolean readMore = false;
int height;
if (type == CandidatesViewManager.VIEW_TYPE_CLOSE) {
mViewBody.setVisibility(View.GONE);
return false;
}
mViewBody.setVisibility(View.VISIBLE);
if (mPortrait) {
if (type == CandidatesViewManager.VIEW_TYPE_NORMAL) {
mViewBodyScroll.scrollTo(0, 0);
height = LINE_HEIGHT * LINE_NUM_PORTRAIT;
mViewBodyText.setMaxLines(LINE_NUM_PORTRAIT);
mViewBodyText.setLines(LINE_NUM_PORTRAIT);
if (mWordCount > 1) {
int displayEndCount = (mWordCountInNormalView != -1) ? mWordCountInNormalView : mWordCount;
int endPosition = mEndPositionArray.get(displayEndCount - 1);
mViewBodyText.setText(mCandidates.subSequence(0, endPosition));
mViewBodyText.setSelection(0, 0);
mViewBodyText.setCursorVisible(false);
}
mViewBodyText.setMinimumHeight(height);
} else {
height = LINE_HEIGHT * LINE_NUM_PORTRAIT_FULL;
mViewBodyText.setMaxLines(DISPLAY_LINE_MAX_COUNT);
readMore = true;
mViewBodyText.setMinimumHeight(height);
}
} else {
if (type == CandidatesViewManager.VIEW_TYPE_NORMAL) {
mViewBodyScroll.scrollTo(0, 0);
height = LINE_HEIGHT * LINE_NUM_LANDSCAPE;
mViewBodyText.setMaxLines(LINE_NUM_LANDSCAPE);
mViewBodyText.setLines(LINE_NUM_LANDSCAPE);
if (mWordCount > 1) {
int displayEndCount = (mWordCountInNormalView != -1) ? mWordCountInNormalView : mWordCount;
int endPosition = mEndPositionArray.get(displayEndCount - 1);
mViewBodyText.setText(mCandidates.subSequence(0, endPosition));
mViewBodyText.setSelection(0, 0);
mViewBodyText.setCursorVisible(false);
}
mViewBodyText.setMinimumHeight(height);
} else {
height = LINE_HEIGHT * LINE_NUM_LANDSCAPE_FULL * ((!mHardKeyboardHidden) ? 2 : 1);
mViewBodyText.setMaxLines(DISPLAY_LINE_MAX_COUNT);
readMore = true;
mViewBodyText.setMinimumHeight(height);
}
}
mViewBody.updateViewLayout(mViewBodyScroll,
new FrameLayout.LayoutParams(mViewWidth, height));
mViewHeight = height;
return readMore;
}
/** @see CandidatesViewManager#getViewType */
public int getViewType() {
return mViewType;
}
/** @see CandidatesViewManager#displayCandidates */
public void displayCandidates(WnnEngine converter) {
mCanReadMore = false;
mDisplayEndOffset = 0;
mIsFullView = false;
int maxLine = getMaxLine();
displayCandidates(converter, true, maxLine);
}
/** @see CandidatesViewManager#getMaxLine */
private int getMaxLine() {
int maxLine = (mPortrait) ? LINE_NUM_PORTRAIT : LINE_NUM_LANDSCAPE;
return maxLine;
}
/**
* Add a new line if necessary.
*/
private void addNewlineIfNecessary() {
int maxLine = getMaxLine();
int lineNum = mViewBodyText.getLineCount();
if (lineNum == 0) {
lineNum = countLineUsingMeasureText(mViewBodyText.getText());
}
int textLength = mViewBodyText.length();
for (int i = 0; i < 3; i++) {
mPositionToWordIndexArray.add(textLength + i,-1);
}
for (int i = 0; i < maxLine - lineNum; i++) {
mViewBodyText.append("\n");
}
if (mPortrait && maxLine == -1 && lineNum == 1) {
mViewBodyText.append("\n");
}
return;
}
/**
* Count lines using {@link Paint#measureText}.
*
* @param text The text to display
* @return Number of lines
*/
private int countLineUsingMeasureText(CharSequence text) {
StringBuffer tmpText = new StringBuffer(text);
mStartPositionArray.add(mWordCount,tmpText.length());
int padding =
ViewConfiguration.getScrollBarSize() +
mViewBodyText.getPaddingLeft() +
mViewBodyText.getPaddingRight();
TextPaint p = mViewBodyText.getPaint();
int lineCount = 1;
int start = 0;
for (int i = 0; i < mWordCount; i++) {
if (tmpText.length() < start ||
tmpText.length() < mStartPositionArray.get(i + 1)) {
return 1;
}
float lineLength = measureText(p, tmpText, start, mStartPositionArray.get(i + 1));
if (lineLength > (mViewWidth - padding)) {
lineCount++;
start = mStartPositionArray.get(i);
i--;
}
}
return lineCount;
}
/**
* Display the candidates.
*
* @param converter {@link WnnEngine} which holds candidates.
* @param dispFirst Whether it is the first time displaying the candidates
* @param maxLine The maximum number of displaying lines
*/
synchronized private void displayCandidates(WnnEngine converter, boolean dispFirst, int maxLine) {
if (converter == null) {
return;
}
mHasStartedSelect = false;
/* Clear for the first time */
if (dispFirst) {
clearCandidates();
this.mConverter = converter;
mLastWord = null;
mHasCreatedCandidateList = true;
}
/* Concatenate the candidates already got and the last one in dispFirst mode */
boolean category = false;
StringBuffer tmp = new StringBuffer();
tmp.append(mCandidates);
if ((!dispFirst) && (mLastWord != null) && (mLastWord.candidate.length() != 0)) {
mLineWordCount = -1;
StringBuffer displayText = createDisplayText(mLastWord, maxLine);
if (category) {
tmp.append(displayText);
category = false;
} else {
mWnnWordArray.add(mWordCount, mLastWord);
int i = 0;
for (i = 0 ; i < tmp.length(); i++) {
if (!displayText.subSequence(i, i + 1).equals("\n")) {
break;
}
}
mStartPositionArray.add(mWordCount, tmp.length() + i);
tmp.append(displayText);
mEndPositionArray.add(mWordCount, tmp.length());
tmp.append(CANDIDATE_SEPARATOR);
mWordCount++;
}
mLastWord = null;
}
int displayLimit = mDisplayLimit;
StringBuffer displayText;
/* Get candidates */
WnnWord result;
while ((result = converter.getNextCandidate()) != null && (displayLimit == -1 || mWordCount < displayLimit)) {
displayText = createDisplayText(result, maxLine);
if (displayText == null) {
continue;
}
mWnnWordArray.add(mWordCount, result);
int i = 0;
for (i = 0 ; i < tmp.length(); i++) {
if (!displayText.subSequence(i, i + 1).equals("\n")) {
break;
}
}
mStartPositionArray.add(mWordCount, tmp.length() + i);
tmp.append(displayText);
mEndPositionArray.add(mWordCount,tmp.length());
tmp.append(CANDIDATE_SEPARATOR);
mWordCount++;
if (mIsFullView) {
continue;
}
mViewBodyText.setText(tmp);
int lineNum = mViewBodyText.getLineCount();
if (lineNum == 0) {
lineNum = countLineUsingMeasureText(mViewBodyText.getText());
if (lineNum == -1) {
return;
}
}
if (dispFirst && lineNum > maxLine) {
if (mWordCount == 1) {
setViewLayout(CandidatesViewManager.VIEW_TYPE_FULL);
maxLine = -1;
mIsFullView = true;
continue;
}
mCanReadMore = true;
mLastWord = result;
if (mWordCount > 1) {
tmp.delete(mStartPositionArray.get(mWordCount - 1), tmp.length());
mWnnWordArray.remove(mWordCount -1);
mStartPositionArray.remove(mWordCount -1);
mEndPositionArray.remove(mWordCount -1);
} else {
return;
}
mWordCount--;
mWordCountInNormalView = mWordCount;
break;
} else {
if (mWordCount == 1) {
setViewLayout(CandidatesViewManager.VIEW_TYPE_NORMAL);
}
}
}
/* save the candidate string */
mCandidates.delete(0, mCandidates.length());
mCandidates.append(tmp);
int j = 0;
for (int i = 0; i < mWordCount; i++) {
while (j <= mEndPositionArray.get(i)) {
if (j < mStartPositionArray.get(i)) {
mPositionToWordIndexArray.add(j,-1);
} else {
mPositionToWordIndexArray.add(j,i);
}
j++;
}
mPositionToWordIndexArray.add(j,-1);
mPositionToWordIndexArray.add(j + 1,-1);
}
if (mAutoHideMode && mWordCount < 1) {
mWnn.setCandidatesViewShown(false);
return;
}
int displayEndCount =
((mViewType == CandidatesViewManager.VIEW_TYPE_NORMAL) &&
(mWordCountInNormalView != -1))
? mWordCountInNormalView : mWordCount;
int endPosition = mEndPositionArray.get(displayEndCount - 1);
endPosition += CANDIDATE_SEPARATOR.length();
if (mDisplayEndOffset > 0 && maxLine != -1) {
mCanReadMore = true;
String str = mCandidates.substring(0, mDisplayEndOffset);
StringBuffer sub = new StringBuffer(str);
sub.append(CANDIDATE_SEPARATOR);
mViewBodyText.setText(sub.subSequence(0, mDisplayEndOffset + CANDIDATE_SEPARATOR.length()));
} else {
mViewBodyText.setText(mCandidates.subSequence(0, endPosition));
addNewlineIfNecessary();
}
/* Set EditText */
mViewBodyText.setSelection(0, 0);
mViewBodyText.setCursorVisible(false);
mViewBodyText.requestFocus();
setReadMore();
if (!(mViewBody.isShown())) {
mWnn.setCandidatesViewShown(true);
}
return;
}
/**
* Display {@code mReadMoreText} if there are more candidates.
*
*/
private void setReadMore() {
if (mCanReadMore && !mIsFullView && !mCandidateDeleteState) {
mReadMoreText.setHeight(mViewHeight);
mReadMoreText.setVisibility(View.VISIBLE);
} else {
mReadMoreText.setVisibility(View.GONE);
}
}
/**
* Create the string to show in the candidate window.
*
* @param word A candidate word
* @param maxLine The maximum number of line in the candidate window
* @return The string to show
*/
private StringBuffer createDisplayText(WnnWord word, int maxLine) {
StringBuffer tmp = new StringBuffer();
int padding = ViewConfiguration.getScrollBarSize() +
mViewBodyText.getPaddingLeft() +
mViewBodyText.getPaddingRight();
int width = mViewWidth - padding;
TextPaint p = mViewBodyText.getPaint();
float newLineLength = measureText(p, word.candidate, 0, word.candidate.length());
float separatorLength = measureText(p, CANDIDATE_SEPARATOR, 0, CANDIDATE_SEPARATOR.length());
boolean isFirstWordOfLine = (mLineLength == 0);
int maxWidth = 0;
int lineLength = 0;
lineLength += newLineLength;
maxWidth += width - separatorLength;
mLineLength += newLineLength;
mLineLength += separatorLength;
mLineWordCount++;
if (mLineWordCount == 0) {
mLineLength = lineLength;
mLineLength += separatorLength;
}
if (!isFirstWordOfLine && (width < mLineLength) && mLineWordCount != 0) {
tmp.append("\n");
mLineLength = lineLength;
mLineLength += separatorLength;
mLineWordCount = 0;
}
return adjustDisplaySize(word, tmp, lineLength, maxWidth, maxLine);
}
/**
* Adjust the width of specified string
*
* @param word A candidate word
* @param tmp A work area
* @param newLineLength The line length to show
* @param maxwidth The maximum number of width that can be displayed in the candidate window
* @param maxLine The maximum number of line in the candidate window
* @return The string to show
*/
private StringBuffer adjustDisplaySize(WnnWord word, StringBuffer tmp, int newLineLength, int maxWidth, int maxLine) {
StringBuffer string = new StringBuffer(tmp);
if (newLineLength > maxWidth) {
TextPaint p = mViewBodyText.getPaint();
float separatorLength = measureText(p, CANDIDATE_SEPARATOR, 0, CANDIDATE_SEPARATOR.length());
int length = word.candidate.length();
int size = 0;
int count = 0;
int line = 0;
float LineLength = 0;
for (int i = 0 ; i < length;i++) {
string.append(word.candidate.charAt(i));
LineLength = measureText(p, string, count, count + 1);
size += LineLength;
if (size > maxWidth) {
line++;
string.delete(string.length() - 1, string.length());
if (mDisplayEndOffset == 0 && line == maxLine && mWordCount == 0) {
mDisplayEndOffset = count;
}
string.append("\n");
string.append(word.candidate.charAt(i));
size = 0;
count++;
LineLength = measureText(p, string, count, count + 1);
size += LineLength;
}
count++;
}
mLineWordCount = 0;
mLineLength = newLineLength;
mLineLength += separatorLength;
} else {
string.append(word.candidate);
}
return string;
}
/** @see CandidatesViewManager#clearCandidates */
public void clearCandidates() {
mViewBodyText.setText("");
mCandidates.delete(0, mCandidates.length());
mWordCount = 0;
mWordCountInNormalView = -1;
mStartPositionArray.clear();
mEndPositionArray.clear();
mPositionToWordIndexArray.clear();
mWnnWordArray.clear();
mLineLength = 0;
mLineWordCount = -1;
if (mAutoHideMode) {
setViewLayout(CandidatesViewManager.VIEW_TYPE_CLOSE);
}
if (mCandidateDeleteState) {
mViewBodyScroll.removeAllViews();
mViewBodyScroll.addView(mViewBodyText);
}
mCandidateDeleteState = false;
mHasCreatedCandidateList = false;
if (mAutoHideMode && mViewBody.isShown()) {
mWnn.setCandidatesViewShown(false);
}
if (!mAutoHideMode) {
mCanReadMore = false;
setReadMore();
}
}
/** @see CandidatesViewManager#setPreferences */
public void setPreferences(SharedPreferences pref) {
try {
if (pref.getBoolean("key_vibration", false)) {
mVibrator = (Vibrator)mWnn.getSystemService(Context.VIBRATOR_SERVICE);
} else {
mVibrator = null;
}
if (pref.getBoolean("key_sound", false)) {
mSound = MediaPlayer.create(mWnn, R.raw.type);
} else {
mSound = null;
}
} catch (Exception ex) {
Log.d("iwnn", "NO VIBRATOR");
}
}
/**
* @see OnTouchListener#onTouch
*/
public boolean onTouch(View v, MotionEvent event) {
if (mMotionEvent != null) {
return true;
}
mMotionEvent = event;
boolean ret = mWnn.onEvent(new OpenWnnEvent(OpenWnnEvent.CANDIDATE_VIEW_TOUCH));
mMotionEvent = null;
return ret;
}
/**
* Process CANDIDATE_VIEW_TOUCH event.
*
* @return {@code true} if event is processed; {@code false} if otherwise
*/
public boolean onTouchSync() {
if (!mHasCreatedCandidateList) {
return false;
}
mViewBodyText.setCursorVisible(false);
return mGestureDetector.onTouchEvent(mMotionEvent);
}
/**
* Select a candidate.
* <br>
* This method notices the selected word to {@link OpenWnn}.
*
* @param word The selected word
*/
private void selectCandidate(WnnWord word) {
setViewLayout(CandidatesViewManager.VIEW_TYPE_NORMAL);
if (mVibrator != null) {
try { mVibrator.vibrate(30); } catch (Exception ex) { }
}
if (mSound != null) {
try { mSound.seekTo(0); mSound.start(); } catch (Exception ex) { }
}
mWnn.onEvent(new OpenWnnEvent(OpenWnnEvent.SELECT_CANDIDATE, word));
}
/**
* Convert a coordinate into the offset of character
*
* @param x The horizontal position
* @param y The vertical position
* @return The offset of character
*/
public int getOffset(int x,int y){
Layout layout = mViewBodyText.getLayout();
int line = layout.getLineForVertical(y);
if( y >= layout.getLineTop(line+1) ){
return layout.getText().length();
}
int offset = layout.getOffsetForHorizontal(line,x);
offset -= TOUCH_ADJUSTED_VALUE;
if (offset < 0) {
offset = 0;
}
return offset;
}
/** from GestureDetector.OnGestureListener class */
public boolean onDown(MotionEvent arg0) {
if (!mCandidateDeleteState) {
int position = getOffset((int)arg0.getX(),(int)arg0.getY());
int wordIndex = mPositionToWordIndexArray.get(position);
if (wordIndex != -1) {
int startPosition = mStartPositionArray.get(wordIndex);
int endPosition = 0;
if (mDisplayEndOffset > 0 && getViewType() == CandidatesViewManager.VIEW_TYPE_NORMAL) {
endPosition = mDisplayEndOffset + CANDIDATE_SEPARATOR.length();
} else {
endPosition = mEndPositionArray.get(wordIndex);
}
mViewBodyText.setSelection(startPosition, endPosition);
mViewBodyText.setCursorVisible(true);
mViewBodyText.invalidate();
mHasStartedSelect = true;
}
}
return true;
}
/** from GestureDetector.OnGestureListener class */
public boolean onFling(MotionEvent arg0, MotionEvent arg1, float arg2, float arg3) {
if (mCandidateDeleteState) {
return false;
}
boolean consumed = false;
if (arg1.getY() < arg0.getY()) {
if (mViewType == CandidatesViewManager.VIEW_TYPE_NORMAL) {
if (mVibrator != null) {
try { mVibrator.vibrate(30); } catch (Exception ex) { }
}
mIsFullView = true;
mWnn.onEvent(new OpenWnnEvent(OpenWnnEvent.LIST_CANDIDATES_FULL));
consumed = true;
}
} else {
if (mViewBodyScroll.getScrollY() == 0) {
if (mVibrator != null) {
try { mVibrator.vibrate(30); } catch (Exception ex) { }
}
mIsFullView = false;
mWnn.onEvent(new OpenWnnEvent(OpenWnnEvent.LIST_CANDIDATES_NORMAL));
consumed = true;
}
}
return consumed;
}
/** from GestureDetector.OnGestureListener class */
public void onLongPress(MotionEvent arg0) {
if (!mHasStartedSelect) {
return;
}
mWord = null;
int position = getOffset((int)arg0.getX(),(int)arg0.getY());
if (position < mPositionToWordIndexArray.size()) {
int wordIndex = mPositionToWordIndexArray.get(position);
if (wordIndex != -1) {
mCandidateDeleteState = true;
mViewBodyScroll.removeAllViews();
mViewBody.updateViewLayout(mViewBodyScroll,
new FrameLayout.LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.WRAP_CONTENT));
setReadMore();
mWord = mWnnWordArray.get(wordIndex);
LinearLayout mLinerLayout;
mLinerLayout = new LinearLayout(mViewBodyScroll.getContext());
mLinerLayout.setOrientation(LinearLayout.VERTICAL);
Resources r = mViewBodyScroll.getContext().getResources();
int color = r.getColor(R.color.candidate_background);
mLinerLayout.setBackgroundColor(color);
TextView text = new TextView(mViewBodyScroll.getContext());
text.setText(mWord.candidate);
text.setTextColor(mWnn.getResources().getColor(R.color.candidate_text));
text.setTextSize(mWnn.getResources().getDimension(R.dimen.candidate_delete_word_size));
text.setGravity(Gravity.CENTER);
mLinerLayout.addView(text);
LinearLayout linearLayout = new LinearLayout(mViewBodyScroll.getContext());
linearLayout.setOrientation(LinearLayout.HORIZONTAL);
linearLayout.addView(createSelectButton());
linearLayout.addView(createCancelButton());
linearLayout.setGravity(Gravity.CENTER);
mLinerLayout.addView(linearLayout);
mViewBodyScroll.addView(mLinerLayout);
}
}
}
/** from GestureDetector.OnGestureListener class */
public boolean onScroll(MotionEvent arg0, MotionEvent arg1, float arg2,
float arg3) {
return false;
}
/** from GestureDetector.OnGestureListener class */
public void onShowPress(MotionEvent arg0) {
}
/** from GestureDetector.OnGestureListener class */
public boolean onSingleTapUp(MotionEvent arg0) {
if (!mHasStartedSelect) {
return true;
}
WnnWord word = null;
if (!mCandidateDeleteState) {
int position = getOffset((int)arg0.getX(),(int)arg0.getY());
if (position < mPositionToWordIndexArray.size()) {
int wordIndex = mPositionToWordIndexArray.get(position);
if (wordIndex != -1) {
word = mWnnWordArray.get(wordIndex);
}
if (word != null) {
selectCandidate(word);
return true;
} else {
return false;
}
}
}
return false;
}
/**
* Create the select button.
*
* @return Button The button object
*/
private Button createSelectButton(){
final Button selectB;
selectB= new Button(mViewBodyScroll.getContext()) {
public boolean onTouchEvent(MotionEvent me) {
boolean ret = super.onTouchEvent(me);
Drawable d = getBackground();
switch (me.getAction()) {
case MotionEvent.ACTION_DOWN:
d.setState(View.PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET);
break;
case MotionEvent.ACTION_UP:
default:
d.clearColorFilter();
break;
}
return ret;
}
};
selectB.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
selectCandidate(mWord);
}
});
selectB.setText(mSelectBottonText);
return selectB;
}
/**
* Create the cancel button
*
* @return Button the button object
*/
private Button createCancelButton(){
final Button cancelB;
cancelB= new Button(mViewBodyScroll.getContext()) {
public boolean onTouchEvent(MotionEvent me) {
boolean ret = super.onTouchEvent(me);
Drawable d = getBackground();
switch (me.getAction()) {
case MotionEvent.ACTION_DOWN:
d.setState(View.PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET);
break;
case MotionEvent.ACTION_UP:
default:
d.clearColorFilter();
break;
}
return ret;
}
};
cancelB.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
setViewLayout(CandidatesViewManager.VIEW_TYPE_NORMAL);
mViewBodyScroll.removeAllViews();
mCandidateDeleteState = false;
mWnn.onEvent(new OpenWnnEvent(OpenWnnEvent.UPDATE_CANDIDATE));
mViewBodyScroll.addView(mViewBodyText);
}
});
cancelB.setText(mCancelBottonText);
return cancelB;
}
/**
* Set the show state of hardware keyboard
*
* @param hidden {@code true} if the hardware keyboard is not shown
*/
public void setHardKeyboardHidden(boolean hidden) {
mHardKeyboardHidden = hidden;
}
/**
* Retrieve the width of string to draw
* (Emoji is supported by this method)
*
* @param paint The information to draw
* @param text The string
* @param start The start position (specified by the number of character)
* @param end The end position (specified by the number of character)
* @return The width of string to draw
*/
public int measureText(TextPaint paint, CharSequence text, int start, int end) {
return (int)Styled.measureText(paint, new TextPaint(), text, start, end, null);
}
}