/* vim:set et ts=4 sts=4: * * ibus-pinyin - The Chinese PinYin engine for IBus * * Copyright (c) 2008-2010 Peng Huang * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "PyZyPhoneticContext.h" #include "PyZySimpTradConverter.h" #include "PyZyDatabase.h" #include "PyZyPhraseEditor.h" namespace PyZy { PhoneticContext::PhoneticContext (Config & config, PhoneticContext::Observer *observer) : m_config (config), m_phrase_editor (config), m_observer (observer) { reset (); } PhoneticContext::~PhoneticContext () { } bool PhoneticContext::processKeyEvent (unsigned short key) { const guint key_code = key & 0x00ff; const guint vkey_code = key & 0xff00; if (vkey_code == 0) { if ('a' <= key_code && key_code <= 'z') { return insert (key_code); } } else { const guint key_num = key_code - '1'; switch (vkey_code) { case VKEY_COMMIT: commit (); return TRUE; case VKEY_RESET: reset (); update (); return TRUE; case VKEY_CURSOR_RIGHT: if (m_phrase_editor.unselectCandidates ()) { update (); return TRUE; } else { return moveCursorRight(); } case VKEY_CURSOR_LEFT: if (m_phrase_editor.unselectCandidates ()) { update (); return TRUE; } else { return moveCursorLeft(); } case VKEY_CURSOR_RIGHT_BY_WORD: if (m_phrase_editor.unselectCandidates ()) { update (); return TRUE; } else { return moveCursorRightByWord (); } case VKEY_CURSOR_LEFT_BY_WORD: if (m_phrase_editor.unselectCandidates ()) { update (); return TRUE; } else { return moveCursorLeftByWord (); } case VKEY_CURSOR_TO_BEGIN: if (m_phrase_editor.unselectCandidates ()) { update (); return TRUE; } else { return moveCursorToBegin(); } case VKEY_CURSOR_TO_END: if (m_phrase_editor.unselectCandidates ()) { update (); return TRUE; } else { return moveCursorToEnd(); } case VKEY_CANDIDATE_SELECT: return selectCandidateInPage (key_num); case VKEY_CANDIDATE_FOCUS: return focusCandidateInPage (key_num); case VKEY_CANDIDATE_RESET: return resetCandidateInPage (key_num); case VKEY_PAGE_PREVIOUS: selectPage (MAX(1, page ()) - 1); return TRUE; case VKEY_PAGE_NEXT: selectPage (page () + 1); return TRUE; case VKEY_PAGE_BEGIN: selectPage (0); return TRUE; case VKEY_PAGE_END: { const guint guint_max = (guint)-1; selectPage (guint_max); } return TRUE; case VKEY_DELETE_CHARACTER_BEFORE: return removeCharBefore(); case VKEY_DELETE_CHARACTER_AFTER: return removeCharAfter(); case VKEY_DELETE_WORD_BEFORE: return removeWordBefore(); case VKEY_DELETE_WORD_AFTER: return removeWordAfter(); } } g_warning ("Can't handle KeyEvent (keycode=%d, vkeycode=%d)\n", key_code, vkey_code); return FALSE; } gboolean PhoneticContext::updateSpecialPhrases (void) { guint size = m_special_phrases.size (); m_special_phrases.clear (); if (!m_config.specialPhrases ()) return FALSE; if (!m_selected_special_phrase.empty ()) return FALSE; guint begin = m_phrase_editor.cursorInChar (); guint end = m_cursor; if (begin < end) { SpecialPhraseTable::instance ().lookup ( m_text.substr (begin, m_cursor - begin), m_special_phrases); } return size != m_special_phrases.size () || size != 0; } void PhoneticContext::updateLookupTable (void) { m_candidates.clear (); for (gint i = 0; i < m_special_phrases.size (); ++i) { Candidate candidate; candidate.text = m_special_phrases[i]; candidate.type = SPECIAL_PHRASE; m_candidates.push_back (candidate); } const PhraseArray & phrase_array = m_phrase_editor.candidates (); for (gint i = 0; i < phrase_array.size (); ++i) { CandidateType candidate_type; if (i < m_special_phrases.size ()) { candidate_type = SPECIAL_PHRASE; } else if (m_phrase_editor.candidateIsUserPhrase (i - m_special_phrases.size ())) { candidate_type = USER_PHRASE; } else { candidate_type = NORMAL_PHRASE; } Candidate candidate; candidate.text = phrase_array[i].phrase; candidate.type = candidate_type; m_candidates.push_back (candidate); } m_observer->lookupTableChanged (); } void PhoneticContext::reset (void) { m_pinyin.clear (); m_pinyin_len = 0; m_phrase_editor.reset (); m_special_phrases.clear (); m_selected_special_phrase.clear (); m_cursor = 0; m_focused_candidate = 0; m_text.clear (); m_preedit_text.clear (); } gboolean PhoneticContext::focusCandidateInPage (guint i) { return focusCandidate (page () * m_config.pageSize () + i); } gboolean PhoneticContext::focusCandidate (guint i) { if (G_UNLIKELY (i >= m_candidates.size ())) { g_warning ("Too big index. Can't focus to selected candidate."); return FALSE; } m_focused_candidate = i; update (); return TRUE; } void PhoneticContext::selectPage (guint i) { if (G_UNLIKELY (m_candidates.size () == 0)) { m_focused_candidate = 0; return; } const guint size = m_config.pageSize (); const guint max_page = (m_candidates.size () - 1) / size; if (i > max_page) { i = max_page; } m_focused_candidate = MIN (m_candidates.size (), i * size + m_focused_candidate % size); update (); } void PhoneticContext::update () { updateLookupTable (); updatePreeditText (); updateAuxiliaryText (); } gboolean PhoneticContext::selectCandidate (guint i) { if (i >= m_config.pageSize ()) { g_warning ("selectCandidate(%ud): Too big index!\n", i); } if (i < m_special_phrases.size ()) { // select a special phrase m_selected_special_phrase = m_special_phrases[i]; m_focused_candidate = 0; if (m_cursor == m_text.size ()) { commit (); } else { updateSpecialPhrases (); update (); } return TRUE; } i -= m_special_phrases.size (); if (m_phrase_editor.selectCandidate (i)) { m_focused_candidate = 0; if (m_phrase_editor.pinyinExistsAfterCursor () || *textAfterPinyin () != '\0') { updateSpecialPhrases (); update (); } else { commit (); } return TRUE; } return FALSE; } gboolean PhoneticContext::selectCandidateInPage (guint i) { return selectCandidate (page () * m_config.pageSize () + i); } gboolean PhoneticContext::resetCandidate (guint i) { if (i < m_special_phrases.size ()) { return FALSE; } i -= m_special_phrases.size (); if (m_phrase_editor.resetCandidate (i)) { update (); } return TRUE; } gboolean PhoneticContext::resetCandidateInPage (guint i) { return resetCandidate (page () * m_config.pageSize () + i); } }; // namespace PyZy