1 /* vim:set et ts=4 sts=4:
3 * ibus-libpinyin - Intelligent Pinyin engine based on libpinyin for IBus
5 * Copyright (c) 2011 Peng Wu <alexepico@gmail.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #include "PYPPhoneticEditor.h"
23 #include "PYPinyinProperties.h"
24 #include "PYSimpTradConverter.h"
28 /* init static members */
29 LibPinyinPhoneticEditor::LibPinyinPhoneticEditor (PinyinProperties &props,
31 Editor (props, config),
33 m_lookup_table (m_config.pageSize ())
35 m_candidates = g_array_new(FALSE, TRUE, sizeof(lookup_candidate_t));
38 LibPinyinPhoneticEditor::~LibPinyinPhoneticEditor (){
39 pinyin_free_candidates (m_instance, m_candidates);
40 g_array_free (m_candidates, TRUE);
45 LibPinyinPhoneticEditor::processSpace (guint keyval, guint keycode,
50 if (cmshm_filter (modifiers) != 0)
53 if (m_lookup_table.size () != 0) {
54 selectCandidate (m_lookup_table.cursorPos ());
65 LibPinyinPhoneticEditor::processFunctionKey (guint keyval, guint keycode, guint modifiers)
71 modifiers = cmshm_filter (modifiers);
73 if (modifiers != 0 && modifiers != IBUS_CONTROL_MASK)
76 /* process some cursor control keys */
77 if (modifiers == 0) { /* no modifiers. */
81 commit (m_text.c_str ());
106 moveCursorToBegin ();
125 case IBUS_KP_Page_Up:
130 case IBUS_KP_Page_Down:
141 } else { /* ctrl key pressed. */
154 moveCursorLeftByWord ();
170 LibPinyinPhoneticEditor::processKeyEvent (guint keyval, guint keycode, guint modifiers)
176 LibPinyinPhoneticEditor::updateLookupTableFast (void)
178 Editor::updateLookupTableFast (m_lookup_table, TRUE);
182 LibPinyinPhoneticEditor::updateLookupTable (void)
184 m_lookup_table.clear ();
186 fillLookupTableByPage ();
187 if (m_lookup_table.size()) {
188 Editor::updateLookupTable (m_lookup_table, TRUE);
195 LibPinyinPhoneticEditor::fillLookupTableByPage (void)
198 guint filled_nr = m_lookup_table.size ();
199 guint page_size = m_lookup_table.pageSize ();
201 /* fill lookup table by libpinyin get candidates. */
202 guint need_nr = MIN (page_size, m_candidates->len - filled_nr);
203 g_assert (need_nr >=0);
208 for (guint i = filled_nr; i < filled_nr + need_nr; i++) {
209 if (i >= m_candidates->len) /* no more candidates */
212 lookup_candidate_t * candidate = &g_array_index
213 (m_candidates, lookup_candidate_t, i);
215 const gchar * phrase_string = candidate->m_phrase_string;
217 /* show get candidates. */
218 if (G_LIKELY (m_props.modeSimp ())) {
219 word = phrase_string;
220 } else { /* Traditional Chinese */
222 SimpTradConverter::simpToTrad (phrase_string, word);
226 m_lookup_table.appendCandidate (text);
233 LibPinyinPhoneticEditor::pageUp (void)
235 if (G_LIKELY (m_lookup_table.pageUp ())) {
236 updateLookupTableFast ();
237 updatePreeditText ();
238 updateAuxiliaryText ();
243 LibPinyinPhoneticEditor::pageDown (void)
245 if (G_LIKELY((m_lookup_table.pageDown ()) ||
246 (fillLookupTableByPage () && m_lookup_table.pageDown()))) {
247 updateLookupTableFast ();
248 updatePreeditText ();
249 updateAuxiliaryText ();
254 LibPinyinPhoneticEditor::cursorUp (void)
256 if (G_LIKELY (m_lookup_table.cursorUp ())) {
257 updateLookupTableFast ();
258 updatePreeditText ();
259 updateAuxiliaryText ();
264 LibPinyinPhoneticEditor::cursorDown (void)
266 if (G_LIKELY ((m_lookup_table.cursorPos () == m_lookup_table.size() - 1) &&
267 (fillLookupTableByPage () == FALSE))) {
271 if (G_LIKELY (m_lookup_table.cursorDown ())) {
272 updateLookupTableFast ();
273 updatePreeditText ();
274 updateAuxiliaryText ();
279 LibPinyinPhoneticEditor::candidateClicked (guint index, guint button, guint state)
281 selectCandidateInPage (index);
285 LibPinyinPhoneticEditor::reset (void)
288 m_lookup_table.clear ();
290 pinyin_free_candidates (m_instance, m_candidates);
291 pinyin_reset (m_instance);
297 LibPinyinPhoneticEditor::update (void)
299 guint lookup_cursor = getLookupCursor ();
300 pinyin_get_candidates (m_instance, lookup_cursor, m_candidates);
302 updateLookupTable ();
303 updatePreeditText ();
304 updateAuxiliaryText ();
308 LibPinyinPhoneticEditor::commit (const gchar *str)
310 StaticText text(str);
315 LibPinyinPhoneticEditor::getPinyinCursor ()
317 /* Translate cursor position to pinyin position. */
318 PinyinKeyPosVector & pinyin_poses = m_instance->m_pinyin_key_rests;
319 guint pinyin_cursor = pinyin_poses->len;
321 guint16 prev_end = 0, cur_end;
322 for (size_t i = 0; i < pinyin_poses->len; ++i) {
323 PinyinKeyPos *pos = &g_array_index
324 (pinyin_poses, PinyinKeyPos, i);
325 cur_end = pos->m_raw_end;
327 if (prev_end <= m_cursor && m_cursor < cur_end)
333 g_assert (pinyin_cursor >= 0);
334 return pinyin_cursor;
338 LibPinyinPhoneticEditor::getLookupCursor (void)
340 PinyinKeyVector & pinyins = m_instance->m_pinyin_keys;
341 guint lookup_cursor = getPinyinCursor ();
342 /* show candidates when pinyin cursor is at end. */
343 if (lookup_cursor == pinyins->len && m_pinyin_len == m_text.length())
345 return lookup_cursor;
349 LibPinyinPhoneticEditor::selectCandidate (guint i)
352 if (G_UNLIKELY (i >= m_candidates->len))
355 guint lookup_cursor = getLookupCursor ();
357 lookup_candidate_t * candidate = &g_array_index
358 (m_candidates, lookup_candidate_t, i);
359 if (BEST_MATCH_CANDIDATE == candidate->m_candidate_type) {
364 lookup_cursor = pinyin_choose_candidate
365 (m_instance, lookup_cursor, candidate);
366 pinyin_guess_sentence (m_instance);
368 PinyinKeyPosVector & pinyin_poses = m_instance->m_pinyin_key_rests;
369 if (lookup_cursor == pinyin_poses->len) {
373 PinyinKeyPos *pos = &g_array_index
374 (pinyin_poses, PinyinKeyPos, lookup_cursor);
375 m_cursor = pos->m_raw_begin;
381 LibPinyinPhoneticEditor::selectCandidateInPage (guint i)
383 guint page_size = m_lookup_table.pageSize ();
384 guint cursor_pos = m_lookup_table.cursorPos ();
386 if (G_UNLIKELY (i >= page_size))
388 i += (cursor_pos / page_size) * page_size;
390 return selectCandidate (i);
394 LibPinyinPhoneticEditor::removeCharBefore (void)
396 if (G_UNLIKELY (m_cursor == 0))
400 m_text.erase (m_cursor, 1);
409 LibPinyinPhoneticEditor::removeCharAfter (void)
411 if (G_UNLIKELY (m_cursor == m_text.length ()))
414 m_text.erase (m_cursor, 1);
423 LibPinyinPhoneticEditor::moveCursorLeft (void)
425 if (G_UNLIKELY (m_cursor == 0))
434 LibPinyinPhoneticEditor::moveCursorRight (void)
436 if (G_UNLIKELY (m_cursor == m_text.length ()))
445 LibPinyinPhoneticEditor::moveCursorToBegin (void)
447 if (G_UNLIKELY (m_cursor == 0))
456 LibPinyinPhoneticEditor::moveCursorToEnd (void)
458 if (G_UNLIKELY (m_cursor == m_text.length ()))
461 m_cursor = m_text.length ();
467 /* move cursor by word functions */
470 LibPinyinPhoneticEditor::getCursorLeftByWord (void)
474 if (G_UNLIKELY (m_cursor > m_pinyin_len)) {
475 cursor = m_pinyin_len;
477 PinyinKeyPosVector & pinyin_poses = m_instance->m_pinyin_key_rests;
478 guint pinyin_cursor = getPinyinCursor ();
479 PinyinKeyPos *pos = &g_array_index
480 (pinyin_poses, PinyinKeyPos, pinyin_cursor);
481 cursor = pos->m_raw_begin;
483 /* cursor at the begin of one pinyin */
484 g_return_val_if_fail (pinyin_cursor > 0, 0);
485 if ( cursor == m_cursor) {
487 (pinyin_poses, PinyinKeyPos, pinyin_cursor - 1);
488 cursor = pos->m_raw_begin;
496 LibPinyinPhoneticEditor::getCursorRightByWord (void)
500 if (G_UNLIKELY (m_cursor > m_pinyin_len)) {
501 cursor = m_text.length ();
503 guint pinyin_cursor = getPinyinCursor ();
504 PinyinKeyPos *pos = &g_array_index
505 (m_instance->m_pinyin_key_rests, PinyinKeyPos, pinyin_cursor);
506 cursor = pos->m_raw_end;
513 LibPinyinPhoneticEditor::removeWordBefore (void)
515 if (G_UNLIKELY (m_cursor == 0))
518 guint cursor = getCursorLeftByWord ();
519 m_text.erase (cursor, m_cursor - cursor);
527 LibPinyinPhoneticEditor::removeWordAfter (void)
529 if (G_UNLIKELY (m_cursor == m_text.length ()))
532 guint cursor = getCursorRightByWord ();
533 m_text.erase (m_cursor, cursor - m_cursor);
540 LibPinyinPhoneticEditor::moveCursorLeftByWord (void)
542 if (G_UNLIKELY (m_cursor == 0))
545 guint cursor = getCursorLeftByWord ();
553 LibPinyinPhoneticEditor::moveCursorRightByWord (void)
555 if (G_UNLIKELY (m_cursor == m_text.length ()))
558 guint cursor = getCursorRightByWord ();