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
17package jp.co.omronsoft.openwnn;
18
19import android.app.Activity;
20import android.app.AlertDialog;
21import android.app.Dialog;
22import android.content.DialogInterface;
23import android.content.Intent;
24import android.content.res.Configuration;
25import android.graphics.Color;
26import android.graphics.Paint.FontMetricsInt;
27import android.os.Bundle;
28import android.text.TextPaint;
29import android.text.TextUtils;
30import android.util.Log;
31import android.view.Display;
32import android.view.Gravity;
33import android.view.Menu;
34import android.view.MenuItem;
35import android.view.MotionEvent;
36import android.view.KeyEvent;
37import android.view.View;
38import android.view.ViewGroup;
39import android.view.Window;
40import android.view.WindowManager;
41import android.view.View.OnFocusChangeListener;
42import android.view.View.OnTouchListener;
43import android.widget.TableLayout;
44import android.widget.TableRow;
45import android.widget.TextView;
46import android.widget.Toast;
47import android.widget.Button;
48
49import java.util.ArrayList;
50import java.util.Arrays;
51import java.util.Comparator;
52
53
54/**
55 * The abstract class for user dictionary tool.
56 *
57 * @author Copyright (C) 2009, OMRON SOFTWARE CO., LTD.  All Rights Reserved.
58 */
59public abstract class UserDictionaryToolsList extends Activity
60    implements View.OnClickListener, OnTouchListener, OnFocusChangeListener {
61
62    /** The class name of the user dictionary tool */
63    protected String  mListViewName;
64    /** The class name of the user dictionary editor */
65    protected String  mEditViewName;
66    /** The package name of the user dictionary editor */
67    protected String  mPackageName;
68
69    /** ID of the menu item (add) */
70    private final int MENU_ITEM_ADD = 0;
71    /** ID of the menu item (edit) */
72    private final int MENU_ITEM_EDIT = 1;
73    /** ID of the menu item (delete) */
74    private final int MENU_ITEM_DELETE = 2;
75    /** ID of the menu item (initialize) */
76    private final int MENU_ITEM_INIT = 3;
77
78    /** ID of the dialog control (confirm deletion) */
79    private final int DIALOG_CONTROL_DELETE_CONFIRM = 0;
80    /** ID of the dialog control (confirm initialize) */
81    private final int DIALOG_CONTROL_INIT_CONFIRM = 1;
82
83    /** The size of font*/
84    private final int WORD_TEXT_SIZE = 16;
85
86    /** The color of background (unfocused item) */
87    private final int UNFOCUS_BACKGROUND_COLOR = 0xFF242424;
88    /** The color of background (focused item) */
89    private final int FOCUS_BACKGROUND_COLOR = 0xFFFF8500;
90
91    /** The minimum count of registered words */
92    private final int MIN_WORD_COUNT = 0;
93    /** The maximum count of registered words */
94    private final int MAX_WORD_COUNT = 100;
95    /** Maximum word count to display */
96    private final int MAX_LIST_WORD_COUNT = 100;
97
98    /** The threshold time of the double tapping */
99    private final int DOUBLE_TAP_TIME = 300;
100
101    /** Widgets which constitute this screen of activity */
102    private Menu mMenu;
103    /** Table layout for the lists */
104    private TableLayout mTableLayout;
105    /** Focusing view */
106    private static View sFocusingView = null;
107    /** Focusing pair view */
108    private static View sFocusingPairView = null;
109
110    /** Objects which control state transitions */
111    private Intent mIntent;
112
113    /** The number of the registered words */
114    private int mWordCount = 0;
115
116    /** The state of "Add" menu item */
117    private boolean mAddMenuEnabled;
118    /** The state of "Edit" menu item */
119    private boolean mEditMenuEnabled;
120    /** The state of "Delete" menu item */
121    private boolean mDeleteMenuEnabled;
122    /** The state of "Initialize" menu item */
123    private boolean mInitMenuEnabled;
124
125    /** {@code true} if the menu option is initialized */
126    private boolean mInitializedMenu = false;
127    /** {@code true} if one of word is selected */
128    private boolean mSelectedWords;
129    /** The viewID which is selected */
130    private int mSelectedViewID = -1;
131    /** The viewID which was selected previously */
132    private static int sBeforeSelectedViewID = -1;
133    /** The time of previous action */
134    private static long sJustBeforeActionTime = -1;
135
136    /** List of the words in the user dictionary */
137    private ArrayList<WnnWord> mWordList = null;
138
139    /** Work area for sorting the word list */
140    private WnnWord[] mSortData;
141
142    /** Whether the view is initialized */
143    private boolean mInit = false;
144
145    /** Page left button */
146    private Button mLeftButton = null;
147
148    /** Page right button */
149    private Button mRightButton = null;
150
151    /** for isXLarge */
152    private static boolean mIsXLarge = false;
153
154    /**
155     * Send the specified event to IME
156     *
157     * @param ev    The event object
158     * @return      {@code true} if this event is processed
159     */
160    protected abstract boolean sendEventToIME(OpenWnnEvent ev);
161    /** Get the comparator for sorting the list */
162    protected abstract Comparator<WnnWord> getComparator();
163
164    /** Show Dialog Num */
165    private int mDialogShow = -1;
166
167    /** @see android.app.Activity#onCreate */
168    @Override protected void onCreate(Bundle savedInstanceState) {
169
170
171        super.onCreate(savedInstanceState);
172
173        /* create XML layout */
174        setContentView(R.layout.user_dictionary_tools_list);
175        mTableLayout = (TableLayout)findViewById(R.id.user_dictionary_tools_table);
176
177        Button b = (Button)findViewById(R.id.user_dictionary_left_button);
178        b.setOnClickListener(new View.OnClickListener() {
179                public void onClick(View v) {
180                    int pos = mWordCount - MAX_LIST_WORD_COUNT;
181                    if (0 <= pos) {
182                        mWordCount = pos;
183                        updateWordList();
184                        mTableLayout.findViewById(1).requestFocus();
185                    }
186                }
187            });
188        mLeftButton = b;
189
190        b = (Button)findViewById(R.id.user_dictionary_right_button);
191        b.setOnClickListener(new View.OnClickListener() {
192                public void onClick(View v) {
193                    int pos = mWordCount + MAX_LIST_WORD_COUNT;
194                    if (pos < mWordList.size()) {
195                        mWordCount = pos;
196                        updateWordList();
197                        mTableLayout.findViewById(1).requestFocus();
198                    }
199                }
200            });
201        mRightButton = b;
202
203    }
204
205    /** @see android.app.Activity#onStart */
206    @Override protected void onStart() {
207        super.onStart();
208        mDialogShow = -1;
209        sBeforeSelectedViewID = -1;
210        sJustBeforeActionTime = -1;
211        mWordList = getWords();
212
213        final TextView leftText = (TextView) findViewById(R.id.user_dictionary_tools_list_title_words_count);
214        leftText.setText(mWordList.size() + "/" + MAX_WORD_COUNT);
215
216        mIsXLarge = ((getResources().getConfiguration().screenLayout &
217                      Configuration.SCREENLAYOUT_SIZE_MASK)
218                      == Configuration.SCREENLAYOUT_SIZE_XLARGE);
219        updateWordList();
220    }
221
222    /**
223     * Called when the system is about to start resuming a previous activity.
224     *
225     * @see android.app.Activity#onPause
226     */
227    @Override protected void onPause() {
228
229        if (mDialogShow == DIALOG_CONTROL_DELETE_CONFIRM) {
230            dismissDialog(DIALOG_CONTROL_DELETE_CONFIRM);
231            mDialogShow = -1;
232        } else if (mDialogShow == DIALOG_CONTROL_INIT_CONFIRM){
233            dismissDialog(DIALOG_CONTROL_INIT_CONFIRM);
234            mDialogShow = -1;
235        }
236
237        super.onPause();
238    }
239
240    /**
241     * Set parameters of table
242     *
243     * @param  w        The width of the table
244     * @param  h        The height of the table
245     * @return          The information of the layout
246     */
247    private TableLayout.LayoutParams tableCreateParam(int w, int h) {
248        return new TableLayout.LayoutParams(w, h);
249    }
250
251    /** @see android.app.Activity#onCreateOptionsMenu */
252    @Override public boolean onCreateOptionsMenu(Menu menu) {
253
254
255        /* initialize the menu */
256        menu.clear();
257        /* set the menu item enable/disable */
258        setOptionsMenuEnabled();
259        /* [menu] add a word */
260        menu.add(0, MENU_ITEM_ADD, 0, R.string.user_dictionary_add)
261            .setIcon(android.R.drawable.ic_menu_add)
262            .setEnabled(mAddMenuEnabled);
263        /* [menu] edit a word */
264        menu.add(0, MENU_ITEM_EDIT, 0, R.string.user_dictionary_edit)
265            .setIcon(android.R.drawable.ic_menu_edit)
266            .setEnabled(mEditMenuEnabled);
267        /* [menu] delete a word */
268        menu.add(0, MENU_ITEM_DELETE, 0, R.string.user_dictionary_delete)
269            .setIcon(android.R.drawable.ic_menu_delete)
270            .setEnabled(mDeleteMenuEnabled);
271        /* [menu] clear the dictionary */
272        menu.add(1, MENU_ITEM_INIT, 0, R.string.user_dictionary_init)
273            .setIcon(android.R.drawable.ic_menu_delete)
274            .setEnabled(mInitMenuEnabled);
275
276        mMenu = menu;
277        mInitializedMenu = true;
278
279
280        return super.onCreateOptionsMenu(menu);
281    }
282
283    /**
284     * Change state of the option menus according to a current state of the list widget
285     */
286    private void setOptionsMenuEnabled() {
287
288
289        /* [menu] add a word */
290        if (mWordList.size() >= MAX_WORD_COUNT) {
291            /* disable if the number of registered word exceeds MAX_WORD_COUNT */
292            mAddMenuEnabled = false;
293        } else {
294            mAddMenuEnabled = true;
295        }
296
297        /* [menu] edit a word/delete a word */
298        if (mWordList.size() <= MIN_WORD_COUNT) {
299            /* disable if no word is registered or no word is selected */
300            mEditMenuEnabled = false;
301            mDeleteMenuEnabled = false;
302        } else {
303            mEditMenuEnabled = true;
304            if (mSelectedWords) {
305                mDeleteMenuEnabled = true;
306            } else {
307                mDeleteMenuEnabled = false;
308            }
309        }
310
311        /* [menu] clear the dictionary (always enabled) */
312        mInitMenuEnabled = true;
313
314    }
315
316    /** @see android.app.Activity#onOptionsItemSelected */
317    @Override public boolean onOptionsItemSelected(MenuItem item) {
318
319        boolean ret;
320        switch (item.getItemId()) {
321        case MENU_ITEM_ADD:
322            /* add a word */
323            wordAdd();
324            ret = true;
325            break;
326
327        case MENU_ITEM_EDIT:
328            /* edit the word (show dialog) */
329            wordEdit(sFocusingView, sFocusingPairView);
330            ret = true;
331            break;
332
333        case MENU_ITEM_DELETE:
334            /* delete the word (show dialog) */
335            showDialog(DIALOG_CONTROL_DELETE_CONFIRM);
336            mDialogShow = DIALOG_CONTROL_DELETE_CONFIRM;
337            ret = true;
338            break;
339
340        case MENU_ITEM_INIT:
341            /* clear the dictionary (show dialog) */
342            showDialog(DIALOG_CONTROL_INIT_CONFIRM);
343            mDialogShow = DIALOG_CONTROL_INIT_CONFIRM;
344            ret = true;
345            break;
346
347        default:
348            ret = false;
349        }
350
351        return ret;
352    }
353
354    /** @see android.app.Activity#onKeyUp */
355    @Override public boolean onKeyUp(int keyCode, KeyEvent event) {
356        /* open the menu if KEYCODE_DPAD_CENTER is pressed */
357        if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
358            openOptionsMenu();
359            return true;
360        }
361         return super.onKeyUp(keyCode, event);
362    }
363
364    /** @see android.app.Activity#onCreateDialog */
365    @Override protected Dialog onCreateDialog(int id) {
366        switch (id) {
367        case DIALOG_CONTROL_DELETE_CONFIRM:
368            return new AlertDialog.Builder(UserDictionaryToolsList.this)
369                .setMessage(R.string.user_dictionary_delete_confirm)
370                .setNegativeButton(android.R.string.cancel, null)
371                .setPositiveButton(android.R.string.ok, mDialogDeleteWords)
372                .setCancelable(true)
373                .create();
374
375        case DIALOG_CONTROL_INIT_CONFIRM:
376            return new AlertDialog.Builder(UserDictionaryToolsList.this)
377                .setMessage(R.string.dialog_clear_user_dictionary_message)
378                .setNegativeButton(android.R.string.cancel, null)
379                .setPositiveButton(android.R.string.ok, mDialogInitWords)
380                .setCancelable(true)
381                .create();
382
383        default:
384            Log.e("OpenWnn", "onCreateDialog : Invaled Get DialogID. ID=" + id);
385            break;
386        }
387
388
389        return super.onCreateDialog(id);
390    }
391
392    /**
393     * Process the event when the button on the "Delete word" dialog is pushed
394     *
395     * @param  dialog    The information of the dialog
396     * @param  button    The button that is pushed
397     */
398    private DialogInterface.OnClickListener mDialogDeleteWords =
399        new DialogInterface.OnClickListener() {
400            public void onClick(DialogInterface dialog, int button) {
401
402                mDialogShow = -1;
403                CharSequence focusString = ((TextView)sFocusingView).getText();
404                CharSequence focusPairString = ((TextView)sFocusingPairView).getText();
405                WnnWord wnnWordSearch = new WnnWord();
406
407                if (mSelectedViewID > MAX_WORD_COUNT) {
408                    wnnWordSearch.stroke = focusPairString.toString();
409                    wnnWordSearch.candidate = focusString.toString();
410                } else {
411                    wnnWordSearch.stroke = focusString.toString();
412                    wnnWordSearch.candidate = focusPairString.toString();
413                }
414                boolean deleted = deleteWord(wnnWordSearch);
415                if (deleted) {
416                    Toast.makeText(getApplicationContext(),
417                                   R.string.user_dictionary_delete_complete,
418                                   Toast.LENGTH_LONG).show();
419                } else {
420                    Toast.makeText(getApplicationContext(),
421                                   R.string.user_dictionary_delete_fail,
422                                   Toast.LENGTH_LONG).show();
423                    return;
424                }
425
426                mWordList = getWords();
427                int size = mWordList.size();
428                if (size <= mWordCount) {
429                    int newPos = (mWordCount - MAX_LIST_WORD_COUNT);
430                    mWordCount = (0 <= newPos) ? newPos : 0;
431                }
432                updateWordList();
433
434                TextView leftText = (TextView) findViewById(R.id.user_dictionary_tools_list_title_words_count);
435                leftText.setText(size + "/" + MAX_WORD_COUNT);
436
437                if (mInitializedMenu) {
438                    onCreateOptionsMenu(mMenu);
439                }
440            }
441        };
442
443    /**
444     * Process the event when the button on the "Initialize" dialog is pushed
445     *
446     * @param  dialog    The information of the dialog
447     * @param  button    The button that is pushed
448     */
449    private DialogInterface.OnClickListener mDialogInitWords =
450        new DialogInterface.OnClickListener() {
451            public void onClick(DialogInterface dialog, int button) {
452
453                mDialogShow = -1;
454                /* clear the user dictionary */
455                OpenWnnEvent ev = new OpenWnnEvent(OpenWnnEvent.INITIALIZE_USER_DICTIONARY, new WnnWord());
456
457                sendEventToIME(ev);
458                /* show the message */
459                Toast.makeText(getApplicationContext(), R.string.dialog_clear_user_dictionary_done,
460                               Toast.LENGTH_LONG).show();
461                mWordList = new ArrayList<WnnWord>();
462                mWordCount = 0;
463                updateWordList();
464                TextView leftText = (TextView) findViewById(R.id.user_dictionary_tools_list_title_words_count);
465                leftText.setText(mWordList.size() + "/" + MAX_WORD_COUNT);
466
467                if (mInitializedMenu) {
468                    onCreateOptionsMenu(mMenu);
469                }
470            }
471        };
472
473
474    /** @see android.view.View.OnClickListener#onClick */
475    public void onClick(View arg0) {
476    }
477
478    /** @see android.view.View.OnTouchListener#onTouch */
479    public boolean onTouch(View v, MotionEvent e) {
480
481
482        mSelectedViewID = ((TextView)v).getId();
483        switch (e.getAction()) {
484        case MotionEvent.ACTION_DOWN:
485            /* double tap handling */
486            if (sBeforeSelectedViewID != ((TextView)v).getId()) {
487                /* save the view id if the id is not same as previously selected one */
488                sBeforeSelectedViewID = ((TextView)v).getId();
489            } else {
490                if ((e.getDownTime() - sJustBeforeActionTime) < DOUBLE_TAP_TIME) {
491                    /* edit the word if double tapped */
492                    sFocusingView = v;
493                    sFocusingPairView = ((UserDictionaryToolsListFocus)v).getPairView();
494                    wordEdit(sFocusingView, sFocusingPairView);
495                }
496            }
497            /* save the action time */
498            sJustBeforeActionTime = e.getDownTime();
499            break;
500        }
501
502        return false;
503    }
504
505    /** @see android.view.View.OnFocusChangeListener#onFocusChange */
506    public void onFocusChange(View v, boolean hasFocus) {
507
508        mSelectedViewID = ((TextView)v).getId();
509        sFocusingView = v;
510        sFocusingPairView = ((UserDictionaryToolsListFocus)v).getPairView();
511        if (hasFocus) {
512            ((TextView)v).setTextColor(Color.BLACK);
513            v.setBackgroundColor(FOCUS_BACKGROUND_COLOR);
514            ((TextView)sFocusingPairView).setTextColor(Color.BLACK);
515            sFocusingPairView.setBackgroundColor(FOCUS_BACKGROUND_COLOR);
516            mSelectedWords = true;
517        } else {
518            mSelectedWords = false;
519            ((TextView)v).setTextColor(Color.LTGRAY);
520            v.setBackgroundColor(UNFOCUS_BACKGROUND_COLOR);
521            ((TextView)sFocusingPairView).setTextColor(Color.LTGRAY);
522            sFocusingPairView.setBackgroundColor(UNFOCUS_BACKGROUND_COLOR);
523        }
524        if (mInitializedMenu) {
525            onCreateOptionsMenu(mMenu);
526        }
527    }
528
529    /**
530     * Add the word
531     */
532    public void wordAdd() {
533        /** change to the edit window */
534        screenTransition(Intent.ACTION_INSERT, mEditViewName);
535    }
536
537    /**
538     * Edit the specified word
539     *
540     * @param  focusView       The information of view
541     * @param  focusPairView   The information of pair of view
542     */
543    public void wordEdit(View focusView, View focusPairView) {
544        if (mSelectedViewID > MAX_WORD_COUNT) {
545            createUserDictionaryToolsEdit(focusPairView, focusView);
546        } else {
547            createUserDictionaryToolsEdit(focusView, focusPairView);
548        }
549        screenTransition(Intent.ACTION_EDIT, mEditViewName);
550    }
551
552    /**
553     * The internal process of editing the specified word
554     *
555     * @param  focusView        The information of view
556     * @param  focusPairView    The information of pair of view
557     */
558    protected abstract UserDictionaryToolsEdit createUserDictionaryToolsEdit(View focusView, View focusPairView);
559
560    /**
561     * Delete the specified word
562     *
563     * @param  searchword   The information of searching
564     * @return          {@code true} if success; {@code false} if fail.
565     */
566    public boolean deleteWord(WnnWord searchword) {
567        OpenWnnEvent event = new OpenWnnEvent(OpenWnnEvent.LIST_WORDS_IN_USER_DICTIONARY,
568                                              WnnEngine.DICTIONARY_TYPE_USER,
569                                              searchword);
570
571        boolean deleted = false;
572        sendEventToIME(event);
573        for( int i=0; i < MAX_WORD_COUNT; i++) {
574            WnnWord getword = new WnnWord();
575            event = new OpenWnnEvent(OpenWnnEvent.GET_WORD,
576                                     getword);
577            sendEventToIME(event);
578            getword = event.word;
579            int len = getword.candidate.length();
580            if (len == 0) {
581                break;
582            }
583            if (searchword.candidate.equals(getword.candidate)) {
584                WnnWord delword = new WnnWord();
585                delword.stroke = searchword.stroke;
586                delword.candidate = searchword.candidate;
587                delword.id = i;
588                event = new OpenWnnEvent(OpenWnnEvent.DELETE_WORD,
589                                         delword);
590                deleted = sendEventToIME(event);
591                break;
592            }
593        }
594
595        if (mInitializedMenu) {
596            onCreateOptionsMenu(mMenu);
597        }
598
599        return deleted;
600    }
601
602
603    /**
604     * Processing the transition of screen
605     *
606     * @param  action       The string of action
607     * @param  classname    The class name
608     */
609    private void screenTransition(String action, String classname) {
610
611        if (action.equals("")) {
612            mIntent = new Intent();
613        } else {
614            mIntent = new Intent(action);
615        }
616        mIntent.setClassName(mPackageName, classname);
617        startActivity(mIntent);
618        finish();
619    }
620
621    /**
622     * Get the list of words in the user dictionary.
623     * @return The list of words
624     */
625    private ArrayList<WnnWord> getWords() {
626        WnnWord word = new WnnWord();
627        OpenWnnEvent event = new OpenWnnEvent(OpenWnnEvent.LIST_WORDS_IN_USER_DICTIONARY,
628                                              WnnEngine.DICTIONARY_TYPE_USER,
629                                              word);
630        sendEventToIME(event);
631
632        ArrayList<WnnWord> list = new ArrayList<WnnWord>();
633        for (int i = 0; i < MAX_WORD_COUNT; i++) {
634            event = new OpenWnnEvent(OpenWnnEvent.GET_WORD, word);
635            if (!sendEventToIME(event)) {
636                break;
637            }
638            list.add(event.word);
639        }
640
641        compareTo(list);
642
643        return list;
644    }
645
646    /**
647     * Sort the list of words
648     * @param array The array list of the words
649     */
650    protected void compareTo(ArrayList<WnnWord> array) {
651        mSortData = new WnnWord[array.size()];
652        array.toArray(mSortData);
653        Arrays.sort(mSortData, getComparator());
654    }
655
656
657    /**
658     * Update the word list.
659     */
660    private void updateWordList() {
661        if (!mInit) {
662            mInit = true;
663            mSelectedViewID = 1;
664
665            Window window = getWindow();
666            WindowManager windowManager = window.getWindowManager();
667            Display display = windowManager.getDefaultDisplay();
668            int system_width = display.getWidth();
669
670            UserDictionaryToolsListFocus dummy = new UserDictionaryToolsListFocus(this);
671            dummy.setTextSize(WORD_TEXT_SIZE);
672            TextPaint paint = dummy.getPaint();
673            FontMetricsInt fontMetrics = paint.getFontMetricsInt();
674            int row_hight = (Math.abs(fontMetrics.top) + fontMetrics.bottom) * 2;
675
676            for (int i = 1; i <= MAX_LIST_WORD_COUNT; i++) {
677                TableRow row = new TableRow(this);
678                UserDictionaryToolsListFocus stroke = new UserDictionaryToolsListFocus(this);
679                stroke.setId(i);
680                stroke.setWidth(system_width/2);
681                stroke.setTextSize(WORD_TEXT_SIZE);
682                stroke.setTextColor(Color.LTGRAY);
683                stroke.setBackgroundColor(UNFOCUS_BACKGROUND_COLOR);
684                stroke.setSingleLine();
685                stroke.setPadding(1,0,1,1);
686                stroke.setEllipsize(TextUtils.TruncateAt.END);
687                stroke.setClickable(true);
688                stroke.setFocusable(true);
689                stroke.setFocusableInTouchMode(true);
690                stroke.setOnTouchListener(this);
691                stroke.setOnFocusChangeListener(this);
692                if (isXLarge()) {
693                    stroke.setHeight(row_hight);
694                    stroke.setGravity(Gravity.CENTER_VERTICAL);
695                }
696
697                UserDictionaryToolsListFocus candidate = new UserDictionaryToolsListFocus(this);
698                candidate.setId(i+MAX_WORD_COUNT);
699                candidate.setWidth(system_width/2);
700                candidate.setTextSize(WORD_TEXT_SIZE);
701                candidate.setTextColor(Color.LTGRAY);
702                candidate.setBackgroundColor(UNFOCUS_BACKGROUND_COLOR);
703                candidate.setSingleLine();
704                candidate.setPadding(1,0,1,1);
705                candidate.setEllipsize(TextUtils.TruncateAt.END);
706                candidate.setClickable(true);
707                candidate.setFocusable(true);
708                candidate.setFocusableInTouchMode(true);
709                candidate.setOnTouchListener(this);
710                candidate.setOnFocusChangeListener(this);
711
712                if (isXLarge()) {
713                    candidate.setHeight(row_hight);
714                    candidate.setGravity(Gravity.CENTER_VERTICAL);
715                }
716                stroke.setPairView(candidate);
717                candidate.setPairView(stroke);
718
719                row.addView(stroke);
720                row.addView(candidate);
721                mTableLayout.addView(row, tableCreateParam(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
722            }
723        }
724
725        int size = mWordList.size();
726        int start = mWordCount;
727
728        TextView t = (TextView)findViewById(R.id.user_dictionary_position_indicator);
729        if (size <= MAX_LIST_WORD_COUNT) {
730            ((View)mLeftButton.getParent()).setVisibility(View.GONE);
731        } else {
732            ((View)mLeftButton.getParent()).setVisibility(View.VISIBLE);
733            int last = (start + MAX_LIST_WORD_COUNT);
734            t.setText((start + 1) + " - " + Math.min(last, size));
735
736            mLeftButton.setEnabled(start != 0);
737            mRightButton.setEnabled(last < size);
738        }
739
740        int selectedId = mSelectedViewID - ((MAX_WORD_COUNT < mSelectedViewID) ? MAX_WORD_COUNT : 0);
741
742        for (int i = 0; i < MAX_LIST_WORD_COUNT; i++) {
743            if ((size - 1) < (start + i)) {
744                if ((0 < i) && (selectedId == (i + 1))) {
745                    mTableLayout.findViewById(i).requestFocus();
746                }
747
748                ((View)(mTableLayout.findViewById(i + 1)).getParent()).setVisibility(View.GONE);
749                continue;
750            }
751
752            WnnWord wnnWordGet;
753            wnnWordGet = mSortData[start + i];
754            int len_stroke = wnnWordGet.stroke.length();
755            int len_candidate = wnnWordGet.candidate.length();
756            if (len_stroke == 0 || len_candidate == 0) {
757                break;
758            }
759
760            if (selectedId == i + 1) {
761                mTableLayout.findViewById(i + 1).requestFocus();
762            }
763
764            TextView text = (TextView)mTableLayout.findViewById(i + 1);
765            text.setText(wnnWordGet.stroke);
766            text = (TextView)mTableLayout.findViewById(i + 1 + MAX_WORD_COUNT);
767            text.setText(wnnWordGet.candidate);
768            ((View)text.getParent()).setVisibility(View.VISIBLE);
769        }
770        mTableLayout.requestLayout();
771    }
772
773    /**
774     * Whether the x large mode.
775     *
776     * @return      {@code true} if x large; {@code false} if not x large.
777     */
778    public static boolean isXLarge() {
779        return mIsXLarge;
780    }
781
782}
783