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