Home | History | Annotate | Download | only in src
      1    0   yongsun /*
      2   82   yongsun  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
      3   82   yongsun  *
      4   82   yongsun  * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
      5   82   yongsun  *
      6   82   yongsun  * The contents of this file are subject to the terms of either the GNU Lesser
      7   82   yongsun  * General Public License Version 2.1 only ("LGPL") or the Common Development and
      8   82   yongsun  * Distribution License ("CDDL")(collectively, the "License"). You may not use this
      9   82   yongsun  * file except in compliance with the License. You can obtain a copy of the CDDL at
     10   82   yongsun  * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
     11   82   yongsun  * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
     12   82   yongsun  * specific language governing permissions and limitations under the License. When
     13   82   yongsun  * distributing the software, include this License Header Notice in each file and
     14   82   yongsun  * include the full text of the License in the License file as well as the
     15   82   yongsun  * following notice:
     16   82   yongsun  *
     17   82   yongsun  * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
     18   82   yongsun  * (CDDL)
     19   82   yongsun  * For Covered Software in this distribution, this License shall be governed by the
     20   82   yongsun  * laws of the State of California (excluding conflict-of-law provisions).
     21   82   yongsun  * Any litigation relating to this License shall be subject to the jurisdiction of
     22   82   yongsun  * the Federal Courts of the Northern District of California and the state courts
     23   82   yongsun  * of the State of California, with venue lying in Santa Clara County, California.
     24   82   yongsun  *
     25   82   yongsun  * Contributor(s):
     26   82   yongsun  *
     27   82   yongsun  * If you wish your version of this file to be governed by only the CDDL or only
     28   82   yongsun  * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
     29   82   yongsun  * include this software in this distribution under the [CDDL or LGPL Version 2.1]
     30   82   yongsun  * license." If you don't indicate a single choice of license, a recipient has the
     31   82   yongsun  * option to distribute your version of this file under either the CDDL or the LGPL
     32   82   yongsun  * Version 2.1, or to extend the choice of license to its licensees as provided
     33   82   yongsun  * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
     34   82   yongsun  * Version 2 license, then the option applies only if the new code is made subject
     35   82   yongsun  * to such option by the copyright holder.
     36    0   yongsun  */
     37   82   yongsun 
     38    0   yongsun #ifdef HAVE_CONFIG_H
     39    0   yongsun #include <config.h>
     40    0   yongsun #endif
     41    0   yongsun 
     42    0   yongsun #include "imi_view_classic.h"
     43    0   yongsun #include "imi_uiobjects.h"
     44    0   yongsun 
     45    0   yongsun #include "imi_keys.h"
     46    0   yongsun 
     47    0   yongsun CIMIClassicView::CIMIClassicView() : CIMIView(),
     48    0   yongsun     m_CursorBone(), m_CursorIdx(0), m_CandiBone(),
     49    0   yongsun     m_CandiList(), m_CandiFirst(0), m_TailSentence()
     50    0   yongsun     { }
     51    0   yongsun 
     52    0   yongsun CIMIClassicView::~CIMIClassicView()
     53    0   yongsun     { }
     54    0   yongsun 
     55    0   yongsun int
     56    0   yongsun CIMIClassicView::getViewType(void)
     57    0   yongsun     { return CIMIViewFactory::SVT_CLASSIC; }
     58    0   yongsun 
     59    0   yongsun 
     60    0   yongsun void
     61    0   yongsun CIMIClassicView::attachIC(CIMIContext* pIC)
     62    0   yongsun {
     63    0   yongsun     CIMIView::attachIC(pIC);
     64    0   yongsun 
     65    0   yongsun     CSunpinyinOptions *ppref = dynamic_cast<CSunpinyinOptions*>(m_pPref);
     66    0   yongsun 
     67    0   yongsun     m_pIC->setLeft2RightSelection(false);
     68    0   yongsun     if (ppref) {
     69    0   yongsun         m_pIC->enableGBK(ppref->m_GBK);
     70    0   yongsun         m_pIC->setHistoryPower(ppref->m_MemoryPower);
     71    0   yongsun         m_pIC->enableContextRanking(ppref->m_ContextRanking);
     72    0   yongsun     }
     73    0   yongsun 
     74    0   yongsun     m_pIC->clear();
     75    0   yongsun     m_CursorBone = m_pIC->getLastBone();
     76    0   yongsun     m_CursorIdx = 0;
     77    0   yongsun     m_CandiBone = m_pIC->getLastBone();
     78    0   yongsun     m_CandiList.clear();
     79    0   yongsun     m_CandiFirst = 0;
     80    0   yongsun }
     81    0   yongsun 
     82    0   yongsun unsigned
     83    0   yongsun CIMIClassicView::clearIC(void)
     84    0   yongsun {
     85    0   yongsun     if (!m_pIC->isEmpty()) {
     86    0   yongsun         m_pIC->clear();
     87    0   yongsun         m_CursorBone = m_pIC->getLastBone();
     88    0   yongsun         m_CursorIdx = 0;
     89    0   yongsun         m_CandiBone = m_pIC->getLastBone();
     90    0   yongsun         m_CandiList.clear();
     91    0   yongsun         m_CandiFirst = 0;
     92    0   yongsun         m_TailSentence.clear();
     93    0   yongsun         return PREEDIT_MASK | CANDIDATE_MASK;
     94    0   yongsun     }
     95    0   yongsun     return 0;
     96    0   yongsun }
     97    0   yongsun 
     98    0   yongsun void
     99    0   yongsun CIMIClassicView::updateWindows(unsigned int mask)
    100    0   yongsun {
    101    0   yongsun     if (mp_winHandler) {
    102    0   yongsun         if ((mask & PREEDIT_MASK) != 0) {
    103    0   yongsun             CPreEditString ps;
    104    0   yongsun             getPreeditString(ps);
    105    0   yongsun             mp_winHandler->updatePreedit(&ps);
    106    0   yongsun         }
    107    0   yongsun 
    108    0   yongsun         if ((mask & PREEDIT_MASK) != 0 || (mask & CANDIDATE_MASK) != 0) {
    109    0   yongsun             int wlen = getSentence(m_TailSentence, m_CandiBone);
    110    0   yongsun             if (wlen <= 1) m_TailSentence.clear();
    111    0   yongsun         }
    112    0   yongsun 
    113    0   yongsun         if ((mask & CANDIDATE_MASK) != 0) {
    114    0   yongsun             CCandidateList cl;
    115    0   yongsun             getCandidateList(cl, m_CandiFirst, s_CandiWindowSize);
    116    0   yongsun             mp_winHandler->updateCandidates(&cl);
    117    0   yongsun         }
    118    0   yongsun     }
    119    0   yongsun }
    120    0   yongsun 
    121    0   yongsun void
    122    0   yongsun CIMIClassicView::commitChar(TWCHAR ch)
    123    0   yongsun {
    124    0   yongsun     TWCHAR wa[2] = {ch, 0};
    125    0   yongsun 
    126    0   yongsun     mp_winHandler->commit(wa);
    127    0   yongsun }
    128    0   yongsun 
    129    0   yongsun void
    130    0   yongsun CIMIClassicView::doCommit(bool bConvert)
    131    0   yongsun {
    132    0   yongsun     wstring bs;
    133    0   yongsun 
    134    0   yongsun     if (bConvert) {
    135    0   yongsun         getIC()->memorize();
    136    0   yongsun         getSentence(bs, m_pIC->getFirstBone());
    137    0   yongsun         mp_winHandler->commit(bs.c_str());
    138    0   yongsun     } else {
    139    0   yongsun         CSkeletonIter ite = m_pIC->getLastBone();
    140    0   yongsun         for (CSkeletonIter it = m_pIC->getFirstBone(); it != ite; ++it) {
    141    0   yongsun             if (it->isPinyinNode())
    142    0   yongsun                 bs += it->m_String;
    143    0   yongsun             else
    144    0   yongsun                 bs += (unsigned)it->m_BoundaryType;
    145    0   yongsun             if (it->isPinyinNode() && it->isUserBoundary())
    146    0   yongsun                 bs += TWCHAR('\'');
    147    0   yongsun         }
    148    0   yongsun         mp_winHandler->commit(bs.c_str());
    149    0   yongsun     }
    150    0   yongsun }
    151    0   yongsun 
    152    0   yongsun int
    153    0   yongsun CIMIClassicView::onKeyEvent(unsigned keycode, unsigned keyvalue, unsigned modifier)
    154    0   yongsun {
    155    0   yongsun     unsigned changeMasks = 0;
    156    0   yongsun     CSunpinyinOptions *ppref = dynamic_cast<CSunpinyinOptions*>(m_pPref);
    157   84  tchaikov 
    158    0   yongsun     //Clear other mask bit we do not care
    159    0   yongsun     modifier &= (IM_SHIFT_MASK | IM_CTRL_MASK | IM_ALT_MASK);
    160   84  tchaikov 
    161    0   yongsun     #ifdef DEBUG
    162    0   yongsun         printf("Classic View got a key (0x%x-0x%x-0x%x)...", keycode, keyvalue, modifier);
    163    0   yongsun 
    164    0   yongsun         if (((modifier & IM_CTRL_MASK) != 0) && (keyvalue == 'P' || keyvalue=='p')) {
    165    0   yongsun             m_pIC->print_lattice();
    166    0   yongsun         }
    167    0   yongsun 
    168    0   yongsun         fflush(stdout);
    169    0   yongsun     #endif
    170    0   yongsun 
    171    0   yongsun     if (keycode == IM_VK_SHIFT && modifier == IM_ALT_MASK) {
    172    0   yongsun         setStatusAttrValue(CIMIWinHandler::STATUS_ID_CN, (!m_CN)?1:0);
    173    0   yongsun         return 0;
    174    0   yongsun     } else if (keyvalue == IM_VK_PERIOD && modifier == IM_CTRL_MASK) {
    175    0   yongsun         // On CTRL+. switch Full/Half punc
    176    0   yongsun         changeMasks |= KEYEVENT_USED;
    177    0   yongsun         setStatusAttrValue(CIMIWinHandler::STATUS_ID_FULLPUNC, (!m_FullPunc)?1:0);
    178    0   yongsun 
    179    0   yongsun     } else if (keyvalue == IM_VK_SPACE && modifier == IM_SHIFT_MASK) {
    180    0   yongsun         // On CTRL+, switch Full/Half simbol
    181    0   yongsun         changeMasks |= KEYEVENT_USED;
    182    0   yongsun         setStatusAttrValue(CIMIWinHandler::STATUS_ID_FULLSIMBOL, (!m_FullSimbol)?1:0);
    183    0   yongsun 
    184    0   yongsun     } else if (modifier == IM_CTRL_MASK && keycode == IM_VK_LEFT) { //move left syllable
    185    0   yongsun         if (!m_pIC->isEmpty()) {
    186    0   yongsun             changeMasks |= KEYEVENT_USED;
    187    0   yongsun             moveLeftSyllable(changeMasks);
    188    0   yongsun         }
    189    0   yongsun 
    190    0   yongsun     } else if (modifier == 0 && keycode == IM_VK_LEFT) { //move left
    191    0   yongsun         if (!m_pIC->isEmpty()) {
    192    0   yongsun             changeMasks |= KEYEVENT_USED;
    193    0   yongsun             moveLeft(changeMasks);
    194    0   yongsun         }
    195    0   yongsun 
    196    0   yongsun     } else if (modifier == IM_CTRL_MASK && keycode == IM_VK_RIGHT) { //move syllable right
    197    0   yongsun         if (!m_pIC->isEmpty()) {
    198    0   yongsun             changeMasks |= KEYEVENT_USED;
    199    0   yongsun             moveRightSyllable(changeMasks);
    200    0   yongsun         }
    201    0   yongsun 
    202    0   yongsun     } else if (modifier == 0 && keycode == IM_VK_RIGHT) { //move right
    203    0   yongsun         if (!m_pIC->isEmpty()) {
    204    0   yongsun             changeMasks |= KEYEVENT_USED;
    205    0   yongsun             moveRight(changeMasks);
    206    0   yongsun         }
    207    0   yongsun 
    208   79  tchaikov     } else if ((ppref != NULL) && (ppref->isPageUpKey(keycode, keyvalue, modifier)) && !m_pIC->isEmpty()) {
    209   79  tchaikov         changeMasks |= KEYEVENT_USED;
    210   79  tchaikov         int sz = m_CandiList.size() + ((m_TailSentence.size() > 0)?1:0);
    211   79  tchaikov         if (sz > 0 && m_CandiFirst > 0) {
    212   79  tchaikov             m_CandiFirst -= s_CandiWindowSize;
    213   79  tchaikov             if (m_CandiFirst < 0) m_CandiFirst = 0;
    214   79  tchaikov             changeMasks |= CANDIDATE_MASK;
    215    0   yongsun         }
    216   79  tchaikov 
    217   79  tchaikov     } else if ((ppref != NULL) && (ppref->isPageDnKey(keycode, keyvalue, modifier)) && !m_pIC->isEmpty()) {
    218   79  tchaikov         changeMasks |= KEYEVENT_USED;
    219   79  tchaikov         int sz = m_CandiList.size() + ((m_TailSentence.size() > 0)?1:0);
    220   79  tchaikov         if (sz > 0 && m_CandiFirst + s_CandiWindowSize < sz) {
    221   79  tchaikov             m_CandiFirst += s_CandiWindowSize;
    222   79  tchaikov             changeMasks |= CANDIDATE_MASK;
    223    0   yongsun         }
    224   79  tchaikov 
    225    0   yongsun     } else if ((modifier & (IM_CTRL_MASK | IM_ALT_MASK)) == 0) {
    226   84  tchaikov         if (islower(keyvalue)) { // insert a PINYIN char
    227    0   yongsun             changeMasks |= KEYEVENT_USED;
    228    0   yongsun             if (m_pIC->getSkeleton().size() < 32) {
    229    0   yongsun                 insertPinyin(keyvalue, changeMasks);
    230    0   yongsun             }
    231    0   yongsun 
    232    0   yongsun         } else if (keycode == IM_VK_BACK_SPACE || keycode == IM_VK_DELETE) { // delete
    233    0   yongsun             if (!m_pIC->isEmpty()) {
    234    0   yongsun                 changeMasks |= KEYEVENT_USED;
    235    0   yongsun                 erase((keycode == IM_VK_BACK_SPACE), changeMasks);
    236    0   yongsun             }
    237    0   yongsun 
    238    0   yongsun         } else if (keycode == IM_VK_HOME) { //move home
    239    0   yongsun             if (!m_pIC->isEmpty()) {
    240    0   yongsun                 changeMasks |= KEYEVENT_USED;
    241    0   yongsun                 moveHome(changeMasks);
    242    0   yongsun             }
    243    0   yongsun         } else if (keycode == IM_VK_END) {  //move end
    244    0   yongsun             if (!m_pIC->isEmpty()) {
    245    0   yongsun                 changeMasks |= KEYEVENT_USED;
    246    0   yongsun                 moveEnd(changeMasks);
    247    0   yongsun             }
    248    0   yongsun 
    249    0   yongsun         } else if (keyvalue == '\'') {
    250    0   yongsun             if (!m_pIC->isEmpty()) {
    251    0   yongsun                 changeMasks |= KEYEVENT_USED;
    252    0   yongsun                 insertBoundary(changeMasks);
    253    0   yongsun             }
    254    0   yongsun 
    255   84  tchaikov         } else if (isdigit(keyvalue) &&
    256   84  tchaikov                    ((s_CandiWindowSize >= 10) ||
    257   85  tchaikov                     (s_CandiWindowSize < 10 && keyvalue < ('1'+s_CandiWindowSize)))) { // try to make selections
    258  118   tonylee #ifdef DEBUG
    259   84  tchaikov             printf("onKeyEvent:number: %d, %d, %d\n", keycode, keyvalue, s_CandiWindowSize);
    260  118   tonylee #endif
    261    0   yongsun             if (!m_pIC->isEmpty()) {
    262    0   yongsun                 changeMasks |= KEYEVENT_USED;
    263  118   tonylee                 unsigned selection = (keyvalue == '0' ? 9 : keyvalue-'1');
    264   85  tchaikov                 makeSelection(selection, changeMasks);
    265    0   yongsun             }
    266    0   yongsun 
    267    0   yongsun         } else if (keyvalue == IM_VK_SPACE) { // select or commit
    268    0   yongsun             if (!m_pIC->isEmpty()) {
    269    0   yongsun                 changeMasks |= KEYEVENT_USED;
    270    0   yongsun                 makeSelection(0, changeMasks);
    271    0   yongsun             }
    272    0   yongsun 
    273    0   yongsun         } else if (keycode == IM_VK_ENTER) { // commit PINYIN string
    274    0   yongsun             if (!m_pIC->isEmpty()) {
    275    0   yongsun                 changeMasks |= KEYEVENT_USED | CANDIDATE_MASK | PREEDIT_MASK;
    276    0   yongsun                 doCommit(false);
    277    0   yongsun                 clearIC();
    278    0   yongsun             }
    279    0   yongsun 
    280    0   yongsun         } else if (keycode == IM_VK_ESCAPE) {
    281    0   yongsun             if (!m_pIC->isEmpty()) {
    282    0   yongsun                 changeMasks |= KEYEVENT_USED | CANDIDATE_MASK | PREEDIT_MASK;
    283    0   yongsun                 clearIC();
    284    0   yongsun             }
    285   84  tchaikov         } else if (keyvalue > 0x20 && keyvalue < 0x7F ) { // isprint() && !isblank()
    286    0   yongsun             if (m_pIC->getSkeleton().size() < 32)
    287    0   yongsun                 pressNormalKey(keyvalue, changeMasks);
    288    0   yongsun             else
    289    0   yongsun                 changeMasks |= KEYEVENT_USED;
    290    0   yongsun         }
    291    0   yongsun     }
    292    0   yongsun 
    293    0   yongsun     #ifdef DEBUG
    294    0   yongsun         printf("   |-->(Mask=0x%x)\n", changeMasks);
    295    0   yongsun         fflush(stdout);
    296    0   yongsun     #endif
    297    0   yongsun 
    298    0   yongsun     updateWindows(changeMasks);
    299    0   yongsun 
    300    0   yongsun     return ((changeMasks & KEYEVENT_USED) != 0)?1:0;
    301    0   yongsun }
    302    0   yongsun 
    303    0   yongsun int
    304    0   yongsun CIMIClassicView::onCandidatePageRequest(int pgno, bool relative)
    305    0   yongsun {
    306    0   yongsun     unsigned changeMasks = 0;
    307    0   yongsun     int      ncandi, lastpgidx;
    308    0   yongsun 
    309    0   yongsun     if (!m_pIC->isEmpty()) {
    310    0   yongsun         changeMasks |= KEYEVENT_USED;
    311    0   yongsun         int sz = m_CandiList.size() + ((m_TailSentence.size() > 0)?1:0);
    312    0   yongsun         if (sz > 0) {
    313    0   yongsun            lastpgidx = (sz-1)/s_CandiWindowSize * s_CandiWindowSize;
    314    0   yongsun            if (relative == true) {
    315    0   yongsun                 ncandi = m_CandiFirst + pgno*s_CandiWindowSize;
    316    0   yongsun                 if (ncandi >= sz)
    317    0   yongsun                    ncandi = lastpgidx;
    318    0   yongsun                 if (ncandi < 0)
    319    0   yongsun                     ncandi =0;
    320    0   yongsun                 if (ncandi != m_CandiFirst) {
    321    0   yongsun                     m_CandiFirst = ncandi;
    322    0   yongsun                     changeMasks |= CANDIDATE_MASK;
    323    0   yongsun                 }
    324    0   yongsun             } else {
    325    0   yongsun                 if (pgno == -1) { //last page
    326    0   yongsun                     ncandi = lastpgidx;
    327    0   yongsun                 } else {
    328    0   yongsun                     ncandi = pgno * s_CandiWindowSize;
    329    0   yongsun                     if (ncandi > lastpgidx)
    330    0   yongsun                         ncandi = lastpgidx;
    331    0   yongsun                 }
    332    0   yongsun                 if (ncandi != m_CandiFirst) {
    333    0   yongsun                     m_CandiFirst = ncandi;
    334    0   yongsun                     changeMasks |= CANDIDATE_MASK;
    335    0   yongsun                 }
    336    0   yongsun             }
    337    0   yongsun         }
    338    0   yongsun     }
    339    0   yongsun 
    340    0   yongsun     updateWindows(changeMasks);
    341    0   yongsun     return 0;
    342    0   yongsun }
    343    0   yongsun 
    344    0   yongsun int
    345    0   yongsun CIMIClassicView::onCandidateSelectRequest(int index)
    346    0   yongsun {
    347    0   yongsun     unsigned changeMasks = 0;
    348    0   yongsun 
    349    0   yongsun     if (!m_pIC->isEmpty()) {
    350    0   yongsun         makeSelection(index, changeMasks);
    351    0   yongsun     }
    352    0   yongsun     updateWindows(changeMasks);
    353    0   yongsun     return 0;
    354    0   yongsun }
    355    0   yongsun 
    356    0   yongsun 
    357    0   yongsun void
    358    0   yongsun CIMIClassicView::pressNormalKey(unsigned keyvalue, unsigned int& mask)
    359    0   yongsun {
    360    0   yongsun     unsigned orig_key = keyvalue;
    361    0   yongsun     unsigned int bone_type = CBone::NODE_ASCII;
    362    0   yongsun 
    363    0   yongsun     if (m_FullSimbol) {
    364    0   yongsun         keyvalue = (unsigned int)(getFullSimbol(TWCHAR(keyvalue)));
    365    0   yongsun     }
    366    0   yongsun     if (m_FullPunc) {
    367    0   yongsun         keyvalue = (unsigned int)(getFullPunc(TWCHAR(keyvalue)));
    368    0   yongsun         bone_type = CBone::NODE_PUNC;
    369    0   yongsun     }
    370    0   yongsun     mask |= KEYEVENT_USED;
    371    0   yongsun     if (m_pIC->isEmpty()) {
    372    0   yongsun         commitChar(TWCHAR(keyvalue));
    373    0   yongsun     } else {
    374    0   yongsun         insertNormalChar(bone_type, orig_key, keyvalue, mask);
    375    0   yongsun     }
    376    0   yongsun }
    377    0   yongsun 
    378    0   yongsun CSkeletonIter
    379    0   yongsun CIMIClassicView::moveLeft(unsigned int& changeMask, bool searchAgain)
    380    0   yongsun {
    381    0   yongsun     CSkeletonIter leftmost = m_pIC->getLastBone();
    382    0   yongsun     if (m_CursorIdx > 0) {
    383    0   yongsun         --m_CursorIdx;
    384    0   yongsun         changeMask |= PREEDIT_MASK;
    385    0   yongsun     } else if (m_CursorBone != m_pIC->getFirstBone()) {
    386    0   yongsun         changeMask |= PREEDIT_MASK;
    387    0   yongsun         if (m_CursorBone-- == m_CandiBone) {
    388    0   yongsun             changeMask |= CANDIDATE_MASK;
    389    0   yongsun             if (m_CursorBone->isValidPinyinNode()) {
    390    0   yongsun                 leftmost = m_CandiBone = m_pIC->cancelSelection(m_CursorBone, searchAgain);
    391    0   yongsun             } else {
    392    0   yongsun                 m_CandiBone = m_CursorBone;
    393    0   yongsun             }
    394    0   yongsun             getCandidates();
    395    0   yongsun         }
    396    0   yongsun 
    397    0   yongsun         m_CursorIdx = m_CursorBone->m_String.size();
    398    0   yongsun         if (!m_CursorBone->isPinyinNode())
    399    0   yongsun             --m_CursorIdx;
    400    0   yongsun     } // else we already at head of the string
    401    0   yongsun     return leftmost;
    402    0   yongsun }
    403    0   yongsun 
    404    0   yongsun CSkeletonIter
    405    0   yongsun CIMIClassicView::moveLeftSyllable(unsigned int& changeMask, bool searchAgain)
    406    0   yongsun {
    407    0   yongsun     CSkeletonIter leftmost = m_pIC->getLastBone();
    408    0   yongsun     if (m_CursorIdx > 0) {
    409    0   yongsun         m_CursorIdx = 0;
    410    0   yongsun         changeMask |= PREEDIT_MASK;
    411    0   yongsun     } else if (m_CursorBone != m_pIC->getFirstBone()) {
    412    0   yongsun         changeMask |= PREEDIT_MASK;
    413    0   yongsun         if (m_CursorBone-- == m_CandiBone) {
    414    0   yongsun             changeMask |= CANDIDATE_MASK;
    415    0   yongsun             if (m_CursorBone->isValidPinyinNode()) {
    416    0   yongsun                 leftmost = m_CandiBone = m_pIC->cancelSelection(m_CursorBone, searchAgain);
    417    0   yongsun             } else {
    418    0   yongsun                 m_CandiBone = m_CursorBone;
    419    0   yongsun             }
    420    0   yongsun             getCandidates();
    421    0   yongsun         }
    422    0   yongsun         m_CursorIdx = 0;
    423    0   yongsun     }  // else we already at head of the string
    424    0   yongsun     return leftmost;
    425    0   yongsun }
    426    0   yongsun 
    427    0   yongsun CSkeletonIter
    428    0   yongsun CIMIClassicView::moveHome(unsigned int& changeMask, bool searchAgain)
    429    0   yongsun {
    430    0   yongsun     CSkeletonIter leftmost = m_pIC->getLastBone();
    431    0   yongsun     CSkeletonIter firstBone = m_pIC->getFirstBone();
    432    0   yongsun 
    433    0   yongsun     if (m_CursorBone != firstBone || m_CursorIdx != 0)
    434    0   yongsun         changeMask |= PREEDIT_MASK;
    435    0   yongsun 
    436    0   yongsun     if (m_CandiBone != firstBone) {
    437    0   yongsun         bool usCanceled = false;
    438    0   yongsun         for (CSkeletonIter bit = m_pIC->getFirstBone(); bit != m_CandiBone; ++bit) {
    439    0   yongsun             if (bit->isValidPinyinNode() && bit->isUserSelectionStart()) {
    440    0   yongsun                 m_pIC->cancelSelection(bit, false);
    441    0   yongsun                 usCanceled = true;
    442    0   yongsun             }
    443    0   yongsun         }
    444    0   yongsun         if (usCanceled) {
    445    0   yongsun             changeMask |= CANDIDATE_MASK;
    446    0   yongsun             leftmost = m_CandiBone = firstBone;
    447    0   yongsun             getCandidates();
    448    0   yongsun             if (searchAgain) m_pIC->searchFrom(firstBone);
    449    0   yongsun         }
    450    0   yongsun     }
    451    0   yongsun     m_CursorIdx = 0;
    452    0   yongsun     m_CursorBone = firstBone;
    453    0   yongsun     return leftmost;
    454    0   yongsun }
    455    0   yongsun 
    456    0   yongsun void
    457    0   yongsun CIMIClassicView::moveRight(unsigned int& changeMask)
    458    0   yongsun {
    459    0   yongsun     CSkeletonIter itLast = m_pIC->getLastBone();
    460    0   yongsun     if (m_CursorBone != itLast) {
    461    0   yongsun         CSkeletonIter itNext = ++CSkeletonIter(m_CursorBone);
    462    0   yongsun         if (m_CursorIdx < m_CursorBone->m_String.size()-1) {
    463    0   yongsun             ++m_CursorIdx;
    464    0   yongsun             changeMask |= PREEDIT_MASK;
    465    0   yongsun         } else if (m_CursorIdx == m_CursorBone->m_String.size()-1) {
    466    0   yongsun             if (m_CursorBone->isPinyinNode()) {
    467    0   yongsun                 ++m_CursorIdx;
    468    0   yongsun                 changeMask |= PREEDIT_MASK;
    469    0   yongsun             } else {
    470    0   yongsun                 m_CursorIdx = 0;
    471    0   yongsun                 ++m_CursorBone;
    472    0   yongsun                 changeMask |= PREEDIT_MASK;
    473    0   yongsun             }
    474    0   yongsun         } else { // m_CursorIdx == m_CursorBone->m_String.size(), must be PinyinNode
    475    0   yongsun             if (itNext != itLast || m_CursorBone->isUserBoundary()) {
    476    0   yongsun                 m_CursorIdx = 0;
    477    0   yongsun                 ++m_CursorBone;
    478    0   yongsun                 changeMask |= PREEDIT_MASK;
    479    0   yongsun             }
    480    0   yongsun         }
    481    0   yongsun     }
    482    0   yongsun }
    483    0   yongsun 
    484    0   yongsun void
    485    0   yongsun CIMIClassicView::moveRightSyllable(unsigned int& changeMask)
    486    0   yongsun {
    487    0   yongsun     CSkeletonIter itLast = m_pIC->getLastBone();
    488    0   yongsun     if (m_CursorBone != itLast) {
    489    0   yongsun         CSkeletonIter itNext = ++CSkeletonIter(m_CursorBone);
    490    0   yongsun         if (itNext == itLast && m_CursorBone->isPinyinNode() && !m_CursorBone->isUserBoundary()) {
    491    0   yongsun             if (m_CursorIdx != m_CursorBone->m_String.size()) {
    492    0   yongsun                 m_CursorIdx = m_CursorBone->m_String.size();
    493    0   yongsun                 changeMask |= PREEDIT_MASK;
    494    0   yongsun             } // else we already at tail
    495    0   yongsun         } else {
    496    0   yongsun             m_CursorIdx = 0;
    497    0   yongsun             ++m_CursorBone;
    498    0   yongsun             changeMask |= PREEDIT_MASK;
    499    0   yongsun         }
    500    0   yongsun     }
    501    0   yongsun }
    502    0   yongsun 
    503    0   yongsun void
    504    0   yongsun CIMIClassicView::moveEnd(unsigned int& changeMask)
    505    0   yongsun {
    506    0   yongsun     CSkeletonIter itLast = m_pIC->getLastBone();
    507    0   yongsun     if (m_CursorBone != itLast) {
    508    0   yongsun         CSkeletonIter itPrev = --CSkeletonIter(itLast);
    509    0   yongsun         if (m_CursorBone != itPrev) {
    510    0   yongsun             m_CursorBone = itPrev;
    511    0   yongsun             m_CursorIdx = 0;
    512    0   yongsun         }
    513    0   yongsun         moveRightSyllable(changeMask);
    514    0   yongsun     }
    515    0   yongsun }
    516    0   yongsun 
    517    0   yongsun void
    518    0   yongsun CIMIClassicView::erase(bool bLeft, unsigned int& changeMask)
    519    0   yongsun {
    520    0   yongsun     if (bLeft && m_CursorBone == m_pIC->getFirstBone() && m_CursorIdx == 0) return;
    521    0   yongsun     if (!bLeft && cursorAtTail()) return;
    522    0   yongsun 
    523    0   yongsun     // default stick direction here
    524    0   yongsun     bool stickLeft = bLeft;
    525    0   yongsun 
    526    0   yongsun     if (bLeft)  moveLeft(changeMask);
    527    0   yongsun 
    528    0   yongsun     changeMask |= PREEDIT_MASK;
    529    0   yongsun     if (m_CursorBone->m_String.size() == m_CursorIdx){
    530    0   yongsun         if (m_CursorBone->m_BoundaryType == CBone::USER_BOUNDARY) {
    531    0   yongsun             CSkeleton skel;
    532    0   yongsun             CSkeletonIter old_cursor = m_CursorBone;
    533    0   yongsun             skel.push_front(*old_cursor);
    534    0   yongsun             skel.front().m_BoundaryType = CBone::AUTO_BOUNDARY;
    535    0   yongsun             m_CursorBone = skel.begin();
    536    0   yongsun             bool upd_candi = m_pIC->modifyAndReseg(
    537    0   yongsun                         old_cursor, ++CSkeletonIter(old_cursor), skel,
    538    0   yongsun                         m_CursorBone, m_CursorIdx, m_CandiBone,
    539    0   yongsun                         stickLeft, true
    540    0   yongsun                     );
    541    0   yongsun             if (upd_candi) getCandidates();
    542    0   yongsun             changeMask |= CANDIDATE_MASK;
    543    0   yongsun         } else {
    544    0   yongsun             if (!bLeft) moveRight(changeMask);
    545    0   yongsun         }
    546    0   yongsun     } else {
    547    0   yongsun         CSkeleton skel;
    548    0   yongsun         CSkeletonIter old_cursor = m_CursorBone;
    549    0   yongsun         skel.push_front(*old_cursor);
    550    0   yongsun         skel.front().m_String.erase(m_CursorIdx, 1);
    551    0   yongsun         if (skel.front().m_String.size() == 0) {
    552    0   yongsun             skel.pop_front();
    553    0   yongsun             m_CursorBone = skel.end();
    554    0   yongsun             m_CursorIdx = 0;
    555    0   yongsun         } else {
    556    0   yongsun             if (m_CursorIdx == 0)
    557    0   yongsun                 stickLeft = false;
    558    0   yongsun             else if (m_CursorIdx == m_CursorBone->m_String.size()-1)
    559    0   yongsun                 stickLeft = true;
    560    0   yongsun             m_CursorBone = skel.begin();
    561    0   yongsun         }
    562    0   yongsun         bool upd_candi = m_pIC->modifyAndReseg(
    563    0   yongsun                     old_cursor, ++CSkeletonIter(old_cursor), skel,
    564    0   yongsun                     m_CursorBone, m_CursorIdx, m_CandiBone,
    565    0   yongsun                     stickLeft, true
    566    0   yongsun                 );
    567    0   yongsun         if (upd_candi) getCandidates();
    568    0   yongsun         changeMask |= CANDIDATE_MASK;
    569    0   yongsun     }
    570    0   yongsun }
    571    0   yongsun 
    572    0   yongsun void
    573    0   yongsun CIMIClassicView::insertPinyin(unsigned int keyvalue, unsigned int& changeMask)
    574    0   yongsun {
    575    0   yongsun     CSkeleton skel;
    576    0   yongsun     CSkeletonIter cursor1 = m_CursorBone, cursor2 = m_CursorBone;
    577    0   yongsun 
    578    0   yongsun     changeMask |= PREEDIT_MASK | CANDIDATE_MASK;
    579    0   yongsun     if (m_CursorBone == m_pIC->getLastBone()) {
    580    0   yongsun         skel.push_front(CBone((const TWCHAR*)&keyvalue, 1, CBone::AUTO_BOUNDARY, CBone::NODE_PINYIN));
    581    0   yongsun         m_CursorBone = skel.begin();
    582    0   yongsun         m_CursorIdx = 1;
    583    0   yongsun     } else if (!m_CursorBone->isPinyinNode()){
    584    0   yongsun         // The cursor could not on the tail of non-pinyin nodes
    585    0   yongsun         if (m_CursorIdx > 0) {
    586    0   yongsun             ++cursor2;
    587    0   yongsun             skel.push_back(CBone(*m_CursorBone));
    588    0   yongsun             skel.back().m_String.erase(m_CursorIdx);
    589    0   yongsun             skel.push_back(CBone((const TWCHAR*)&keyvalue, 1, CBone::AUTO_BOUNDARY, CBone::NODE_PINYIN));
    590    0   yongsun             skel.push_back(CBone(*m_CursorBone));
    591    0   yongsun             skel.back().m_String.erase(0, m_CursorIdx);
    592    0   yongsun             m_CursorBone = skel.begin(); ++m_CursorBone;
    593    0   yongsun             m_CursorIdx = 1;
    594    0   yongsun         } else {
    595    0   yongsun             skel.push_front(CBone((const TWCHAR*)&keyvalue, 1, CBone::AUTO_BOUNDARY, CBone::NODE_PINYIN));
    596    0   yongsun             m_CursorBone = skel.begin();
    597    0   yongsun             m_CursorIdx = 0;
    598    0   yongsun         }
    599    0   yongsun     } else {
    600    0   yongsun         skel.push_front(*m_CursorBone);
    601    0   yongsun         skel.front().m_String.insert(m_CursorIdx, 1, TWCHAR(keyvalue));
    602    0   yongsun         m_CursorBone = skel.begin();
    603    0   yongsun         ++m_CursorIdx;
    604    0   yongsun         ++cursor2;
    605    0   yongsun     }
    606    0   yongsun 
    607    0   yongsun     bool upd_candi = m_pIC->modifyAndReseg(cursor1, cursor2, skel, m_CursorBone, m_CursorIdx, m_CandiBone);
    608    0   yongsun 
    609    0   yongsun     if (upd_candi) getCandidates();
    610    0   yongsun }
    611    0   yongsun 
    612    0   yongsun void
    613    0   yongsun CIMIClassicView::insertBoundary(unsigned int& changeMask)
    614    0   yongsun {
    615    0   yongsun     CSkeletonIter itLast = m_pIC->getLastBone();
    616    0   yongsun     CSkeletonIter itFirst = m_pIC->getFirstBone();
    617    0   yongsun 
    618    0   yongsun     if (m_CursorIdx == 0) {
    619    0   yongsun         if (m_CursorBone != itFirst) {
    620    0   yongsun             CSkeletonIter itPrev = --CSkeletonIter(m_CursorBone);
    621    0   yongsun             if (itPrev->isPinyinNode() && itPrev->isAutoBoundary()) {
    622    0   yongsun                 changeMask |= PREEDIT_MASK; // Only the color of the boundary needed to be updated
    623    0   yongsun                 itPrev->m_BoundaryType = CBone::USER_BOUNDARY;
    624    0   yongsun             }
    625    0   yongsun         }
    626    0   yongsun     } else if (m_CursorBone != itLast && m_CursorIdx == m_CursorBone->m_String.size()) {
    627    0   yongsun         if (m_CursorBone->isAutoBoundary()) { // hidden condition: it is a pinyin node
    628    0   yongsun             changeMask |= PREEDIT_MASK; // Only the color of the boundary needed to be updated
    629    0   yongsun             m_CursorBone->m_BoundaryType = CBone::USER_BOUNDARY;
    630    0   yongsun             moveRight(changeMask);
    631    0   yongsun         }
    632    0   yongsun     } else if (m_CursorBone != itLast && m_CursorIdx < m_CursorBone->m_String.size()) {
    633    0   yongsun         if (m_CursorBone->isPinyinNode()) {
    634    0   yongsun             changeMask |= PREEDIT_MASK | CANDIDATE_MASK;
    635  140   tonylee 
    636  140   tonylee             if (m_CursorBone != itFirst) {
    637  140   tonylee                 bool saveNonCompleteSyllable = m_pIC->canNonCompleteSyllable();
    638  140   tonylee                 m_pIC->setNonCompleteSyllable(false);
    639  140   tonylee                 do { // whether current syllable should be connected with the previous one.
    640  140   tonylee                     CSkeletonIter itPrev = --CSkeletonIter(m_CursorBone);
    641  140   tonylee                     if (!itPrev->isAutoBoundary()) break;
    642  140   tonylee 
    643  140   tonylee                     std::list<CBone> newBones;
    644  140   tonylee                     wstring newSyllable;
    645  140   tonylee 
    646  140   tonylee                     newSyllable.append(m_CursorBone->m_String, 0, m_CursorIdx);
    647  140   tonylee                     m_pIC->segPinyinSimplest(newSyllable, newBones);
    648  140   tonylee                     if ( !(newBones.size() == 0 || newBones.front().m_BoneType == CBone::NODE_INCOMPLETE_PINYIN) ) break;
    649  140   tonylee 
    650  140   tonylee                     newBones.clear();
    651  140   tonylee                     newSyllable.insert(0, itPrev->m_String);
    652  140   tonylee                     m_pIC->segPinyinSimplest(newSyllable, newBones);
    653  140   tonylee                     if (newBones.size() != 1 || newBones.front().m_BoneType != CBone::NODE_PINYIN) break;
    654  140   tonylee 
    655  140   tonylee                     m_pIC->setNonCompleteSyllable(saveNonCompleteSyllable);
    656  140   tonylee 
    657  140   tonylee                     newBones.front().m_BoundaryType = CBone::USER_BOUNDARY;
    658  140   tonylee                     m_pIC->modify(itPrev, m_CursorBone, newBones);
    659  140   tonylee                     if (m_CandiBone == itPrev)
    660  140   tonylee                         m_CandiBone = --CSkeletonIter(m_CursorBone);
    661  140   tonylee 
    662  140   tonylee                     CSkeleton skel;
    663  140   tonylee                     CSkeletonIter cursor1 = m_CursorBone;
    664  140   tonylee                     CSkeletonIter cursor2 = m_CursorBone;
    665  140   tonylee                     ++cursor2;
    666  140   tonylee 
    667  140   tonylee                     skel.push_back(CBone(*m_CursorBone));
    668  140   tonylee                     skel.back().m_String.erase(0, m_CursorIdx);
    669  140   tonylee                     m_CursorBone = skel.begin();
    670  140   tonylee                     m_CursorIdx = 0;
    671  140   tonylee                     m_pIC->modifyAndReseg(
    672  140   tonylee                             cursor1, cursor2, skel,
    673  140   tonylee                             m_CursorBone, m_CursorIdx, m_CandiBone, false
    674  140   tonylee                         );
    675  140   tonylee                     getCandidates();
    676  140   tonylee                     return;
    677  140   tonylee                 } while (false);
    678  140   tonylee                 m_pIC->setNonCompleteSyllable(saveNonCompleteSyllable);
    679  140   tonylee             }
    680  140   tonylee 
    681    0   yongsun             CSkeleton skel;
    682    0   yongsun             CSkeletonIter cursor1 = m_CursorBone;
    683    0   yongsun             CSkeletonIter cursor2 = m_CursorBone;
    684    0   yongsun             ++cursor2;
    685    0   yongsun 
    686    0   yongsun             skel.push_back(CBone(*m_CursorBone));
    687    0   yongsun             skel.back().m_String.erase(m_CursorIdx);
    688    0   yongsun             skel.back().m_BoundaryType = CBone::USER_BOUNDARY;
    689    0   yongsun             skel.push_back(CBone(*m_CursorBone));
    690    0   yongsun             skel.back().m_String.erase(0, m_CursorIdx);
    691    0   yongsun             m_CursorBone = skel.begin();
    692    0   yongsun             ++m_CursorBone;
    693    0   yongsun             m_CursorIdx = 0;
    694    0   yongsun             bool upd_candi = m_pIC->modifyAndReseg(
    695    0   yongsun                     cursor1, cursor2, skel,
    696    0   yongsun                     m_CursorBone, m_CursorIdx, m_CandiBone, false
    697    0   yongsun                 );
    698    0   yongsun             if (upd_candi) getCandidates();
    699    0   yongsun         }
    700    0   yongsun     }
    701    0   yongsun }
    702    0   yongsun 
    703    0   yongsun int
    704    0   yongsun CIMIClassicView::getSentence(wstring& wstr, CSkeletonIter itStart)
    705    0   yongsun {
    706    0   yongsun     return m_pIC->getBestSentence(wstr, itStart, m_pIC->getLastBone());
    707    0   yongsun }
    708    0   yongsun 
    709    0   yongsun void
    710    0   yongsun CIMIClassicView::insertNormalChar(int boneType, unsigned originalKey, unsigned keyvalue, unsigned int& mask)
    711    0   yongsun {
    712    0   yongsun     CSkeleton skel;
    713    0   yongsun     CSkeletonIter cursor1;
    714    0   yongsun     CSkeletonIter cursor2;
    715    0   yongsun     CSkeletonIter ite = m_pIC->getLastBone();
    716    0   yongsun     mask |= PREEDIT_MASK | CANDIDATE_MASK;
    717    0   yongsun     if (m_CursorBone == ite || m_CursorBone->m_String.size() == 0) {
    718    0   yongsun         cursor1 = cursor2 = m_CursorBone;
    719    0   yongsun         skel.push_back(CBone((TWCHAR*)&keyvalue, 1, originalKey, boneType));
    720    0   yongsun     } else if (m_CursorBone != ite && m_CursorBone->m_String.size() == m_CursorIdx) {
    721    0   yongsun         cursor1 = cursor2 = ++m_CursorBone;
    722    0   yongsun         skel.push_back(CBone((TWCHAR*)&keyvalue, 1, originalKey, boneType));
    723    0   yongsun         m_CursorBone = skel.begin();
    724    0   yongsun         ++m_CursorBone;
    725    0   yongsun         m_CursorIdx = 0;
    726    0   yongsun 
    727    0   yongsun     } else {
    728    0   yongsun         cursor1 = cursor2 = m_CursorBone; ++cursor2;
    729    0   yongsun         skel.push_back(CBone(*m_CursorBone));
    730    0   yongsun         skel.back().m_String.erase(m_CursorIdx);
    731    0   yongsun         skel.push_back(CBone((TWCHAR*)&keyvalue, 1, originalKey, boneType));
    732    0   yongsun         skel.push_back(CBone(*m_CursorBone));
    733    0   yongsun         skel.back().m_String.erase(0, m_CursorIdx);
    734    0   yongsun         m_CursorBone = skel.begin();
    735    0   yongsun         ++(++m_CursorBone);
    736    0   yongsun         m_CursorIdx = 0;
    737    0   yongsun     }
    738    0   yongsun     bool upd_candi = m_pIC->modifyAndReseg(cursor1, cursor2, skel, m_CursorBone,
    739    0   yongsun                                            m_CursorIdx, m_CandiBone, false);
    740    0   yongsun     if (upd_candi) getCandidates();
    741    0   yongsun }
    742    0   yongsun 
    743    0   yongsun void
    744    0   yongsun CIMIClassicView::getCandidates()
    745    0   yongsun {
    746    0   yongsun     m_CandiFirst = 0;
    747    0   yongsun     m_pIC->getCandidates(m_CandiBone, m_CandiList);
    748    0   yongsun }
    749    0   yongsun 
    750    0   yongsun bool
    751    0   yongsun CIMIClassicView::cursorAtTail()
    752    0   yongsun {
    753    0   yongsun     CSkeletonIter itLast = m_pIC->getLastBone();
    754    0   yongsun     if (m_CursorBone == itLast)
    755    0   yongsun         return true;
    756    0   yongsun     CSkeletonIter itNext = ++CSkeletonIter(m_CursorBone);
    757    0   yongsun     return (itNext == itLast && m_CursorBone->m_String.size() == m_CursorIdx && !m_CursorBone->isUserBoundary());
    758    0   yongsun     // Hidden condition m_CursorBone->isPinyinNode() == true
    759    0   yongsun }
    760    0   yongsun 
    761    0   yongsun void
    762    0   yongsun CIMIClassicView::makeSelection(int idx, unsigned int& mask)
    763    0   yongsun {
    764    0   yongsun     idx += m_CandiFirst;
    765    0   yongsun     if (m_TailSentence.size() > 0) --idx;
    766    0   yongsun     if (idx < 0) {
    767    0   yongsun         mask |= PREEDIT_MASK | CANDIDATE_MASK;
    768    0   yongsun         doCommit(true);
    769    0   yongsun         clearIC();
    770    0   yongsun     } else if (idx < m_CandiList.size()) {
    771    0   yongsun         mask |= PREEDIT_MASK | CANDIDATE_MASK;
    772    0   yongsun         CCandidate& cand = m_CandiList[idx];
    773    0   yongsun         m_pIC->makeSelection(cand);
    774    0   yongsun         m_CandiBone = cand.m_BoneEnd;
    775    0   yongsun         while (!m_CandiBone->isTailNode() && !m_CandiBone->isPinyinNode())
    776    0   yongsun             ++m_CandiBone;
    777    0   yongsun         if (m_CandiBone->isTailNode()) {
    778    0   yongsun             doCommit(true);
    779    0   yongsun             clearIC();
    780    0   yongsun         } else {
    781    0   yongsun             for (CSkeletonIter it=cand.m_BoneStart; it != m_CandiBone; ++it) {
    782    0   yongsun                 if (m_CursorBone == it) {
    783    0   yongsun                     m_CursorBone = m_CandiBone;
    784    0   yongsun                     m_CursorIdx = 0;
    785    0   yongsun                     break;
    786    0   yongsun                 }
    787    0   yongsun             }
    788    0   yongsun             m_CandiFirst = 0;
    789    0   yongsun             getCandidates();
    790    0   yongsun         }
    791    0   yongsun     }
    792    0   yongsun }
    793    0   yongsun 
    794    0   yongsun void
    795    0   yongsun CIMIClassicView::getPreeditString(IPreeditString& ps)
    796    0   yongsun {
    797    0   yongsun     ps.clear();
    798    0   yongsun 
    799    0   yongsun     wstring & wstr = ps.getString();
    800    0   yongsun     IPreeditString::CCharTypeVec& charTypes = ps.getCharTypeVec();
    801    0   yongsun 
    802    0   yongsun     m_pIC->getBestSentence(wstr, m_pIC->getFirstBone(), m_CandiBone);
    803    0   yongsun 
    804    0   yongsun     int caret = wstr.size();
    805    0   yongsun     charTypes.reserve(caret);
    806    0   yongsun     for (int i=0; i < caret; ++i)
    807    0   yongsun         charTypes.push_back(IPreeditString::HANZI_CHAR | IPreeditString::USER_CHOICE);
    808    0   yongsun     ps.setCandiStart(caret);
    809    0   yongsun 
    810    0   yongsun     CSkeletonIter ite = m_pIC->getLastBone();
    811    0   yongsun     for (CSkeletonIter it = m_CandiBone; it != ite; ) {
    812    0   yongsun         CSkeletonIter curIt = it++;
    813    0   yongsun         if (curIt == m_CursorBone)
    814    0   yongsun             caret = wstr.size() + m_CursorIdx;
    815    0   yongsun 
    816    0   yongsun         if (curIt->isPinyinNode())
    817    0   yongsun             wstr += curIt->m_String;
    818    0   yongsun         else
    819    0   yongsun             wstr.push_back((unsigned)curIt->m_BoundaryType);
    820    0   yongsun 
    821    0   yongsun         int ct = IPreeditString::PINYIN_CHAR;
    822    0   yongsun         if (curIt->m_BoneType == CBone::NODE_INVALID_PINYIN)
    823    0   yongsun             ct |= IPreeditString::ILLEGAL;
    824    0   yongsun         else if (curIt->m_BoneType == CBone::NODE_ASCII)
    825    0   yongsun             ct = IPreeditString::ASCII_CHAR;
    826    0   yongsun         else if (!curIt->isPinyinNode())
    827    0   yongsun             ct = IPreeditString::SIMBOL_CHAR;
    828    0   yongsun 
    829    0   yongsun         for (int i=0; i < curIt->m_String.size(); ++i)
    830    0   yongsun             charTypes.push_back(ct);
    831    0   yongsun 
    832    0   yongsun         if (curIt->isPinyinNode()) {
    833    0   yongsun             if (curIt->m_BoundaryType == CBone::USER_BOUNDARY) {
    834    0   yongsun                 wstr += '\'';
    835    0   yongsun                 charTypes.push_back(IPreeditString::BOUNDARY);
    836    0   yongsun             } else if (it != ite) {
    837    0   yongsun                 wstr += ' ';
    838    0   yongsun                 charTypes.push_back(IPreeditString::BOUNDARY | IPreeditString::USER_CHOICE);
    839    0   yongsun             }
    840    0   yongsun         }
    841    0   yongsun     }
    842    0   yongsun     if (m_CursorBone == ite)
    843    0   yongsun         caret = wstr.size();
    844    0   yongsun     ps.setCaret(caret);
    845    0   yongsun }
    846    0   yongsun 
    847    0   yongsun void
    848    0   yongsun CIMIClassicView::getCandidateList(ICandidateList& cl, int start, int size)
    849    0   yongsun {
    850    0   yongsun     cl.clear();
    851    0   yongsun     cl.reserve(size);
    852    0   yongsun 
    853    0   yongsun     int  tscount = (m_TailSentence.size() > 0)?1:0;
    854    0   yongsun 
    855    0   yongsun     cl.setFirst(start);
    856    0   yongsun     cl.setTotal(tscount + m_CandiList.size());
    857    0   yongsun     ICandidateList::CCandiStrings& css = cl.getCandiStrings();
    858    0   yongsun     ICandidateList::CCandiTypeVec& cts = cl.getCandiTypeVec();
    859    0   yongsun 
    860    0   yongsun     //Loop used for future n-best sentence candidates usage
    861    0   yongsun     for (; start < tscount && size > 0; ++start, --size) {
    862    0   yongsun         css.push_back(m_TailSentence);
    863    0   yongsun         cts.push_back(ICandidateList::BEST_TAIL);
    864    0   yongsun     }
    865    0   yongsun 
    866    0   yongsun     start -= tscount;
    867    0   yongsun     for (int sz=m_CandiList.size(); start < sz && size > 0; ++start, --size) {
    868    0   yongsun         css.push_back(m_CandiList[start].m_String);
    869    0   yongsun         cts.push_back( (start == 0)?(ICandidateList::BEST_WORD):(ICandidateList::NORMAL_WORD) );
    870    0   yongsun     }
    871    0   yongsun }
    872