1 /* vim:set et ts=4 sts=4:
3 * ibus-pinyin - The Chinese PinYin engine 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., 675 Mass Ave, Cambridge, MA 02139, 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(phrase_token_t));
39 LibPinyinPhoneticEditor::processSpace (guint keyval, guint keycode,
44 if (cmshm_filter (modifiers) != 0)
47 if (m_lookup_table.size () != 0) {
48 selectCandidate (m_lookup_table.cursorPos ());
59 LibPinyinPhoneticEditor::processFunctionKey (guint keyval, guint keycode, guint modifiers)
65 modifiers = cmshm_filter (modifiers);
67 if (modifiers != 0 && modifiers != IBUS_CONTROL_MASK)
70 /* process some cursor control keys */
71 if (modifiers == 0) { /* no modifiers. */
75 commit (m_text.c_str ());
100 moveCursorToBegin ();
119 case IBUS_KP_Page_Up:
124 case IBUS_KP_Page_Down:
135 } else { /* ctrl key pressed. */
148 moveCursorLeftByWord ();
164 LibPinyinPhoneticEditor::processKeyEvent (guint keyval, guint keycode, guint modifiers)
170 LibPinyinPhoneticEditor::updateLookupTableFast (void)
172 Editor::updateLookupTableFast (m_lookup_table, TRUE);
176 LibPinyinPhoneticEditor::updateLookupTable (void)
178 m_lookup_table.clear ();
180 fillLookupTableByPage ();
181 if (m_lookup_table.size()) {
182 Editor::updateLookupTable (m_lookup_table, TRUE);
189 LibPinyinPhoneticEditor::fillLookupTableByPage (void)
192 guint filled_nr = m_lookup_table.size ();
193 guint page_size = m_lookup_table.pageSize ();
195 /* fill lookup table by libpinyin guessed sentence and get candidates. */
196 guint need_nr = MIN (page_size, m_candidates->len - filled_nr);
197 g_assert (need_nr >=0);
201 String first_candidate, candidate;
202 for (guint i = filled_nr; i < filled_nr + need_nr; i++) {
203 if (i >= m_candidates->len) /* no more candidates */
206 phrase_token_t *token = &g_array_index
207 (m_candidates, phrase_token_t, i);
209 if (null_token == *token) {
210 /* show the rest of guessed sentence after the cursor. */
213 pinyin_get_sentence(m_instance, &tmp);
217 guint lookup_cursor = getLookupCursor ();
218 candidate = first_candidate = g_utf8_offset_to_pointer
219 (buffer.c_str (), lookup_cursor);
220 if (G_UNLIKELY (!m_props.modeSimp ())) { /* Traditional Chinese */
221 candidate.truncate (0);
222 SimpTradConverter::simpToTrad (first_candidate, candidate);
224 Text text (candidate);
225 m_lookup_table.appendCandidate (text);
231 pinyin_translate_token(m_instance, *token, &word);
234 /* remove duplicated candidates */
235 if (candidate == first_candidate) {
236 g_array_remove_index (m_candidates, i);
241 /* show get candidates. */
242 if (G_UNLIKELY (!m_props.modeSimp ())) { /* Traditional Chinese */
243 candidate.truncate (0);
244 SimpTradConverter::simpToTrad (word, candidate);
246 Text text (candidate);
247 m_lookup_table.appendCandidate (text);
255 LibPinyinPhoneticEditor::pageUp (void)
257 if (G_LIKELY (m_lookup_table.pageUp ())) {
258 updateLookupTableFast ();
259 updatePreeditText ();
260 updateAuxiliaryText ();
265 LibPinyinPhoneticEditor::pageDown (void)
267 if (G_LIKELY((m_lookup_table.pageDown ()) ||
268 (fillLookupTableByPage () && m_lookup_table.pageDown()))) {
269 updateLookupTableFast ();
270 updatePreeditText ();
271 updateAuxiliaryText ();
276 LibPinyinPhoneticEditor::cursorUp (void)
278 if (G_LIKELY (m_lookup_table.cursorUp ())) {
279 updateLookupTableFast ();
280 updatePreeditText ();
281 updateAuxiliaryText ();
286 LibPinyinPhoneticEditor::cursorDown (void)
288 if (G_LIKELY ((m_lookup_table.cursorPos () == m_lookup_table.size() - 1) &&
289 (fillLookupTableByPage () == FALSE))) {
293 if (G_LIKELY (m_lookup_table.cursorDown ())) {
294 updateLookupTableFast ();
295 updatePreeditText ();
296 updateAuxiliaryText ();
301 LibPinyinPhoneticEditor::candidateClicked (guint index, guint button, guint state)
303 selectCandidateInPage (index);
307 LibPinyinPhoneticEditor::reset (void)
310 m_lookup_table.clear ();
311 pinyin_reset (m_instance);
317 LibPinyinPhoneticEditor::update (void)
319 guint lookup_cursor = getLookupCursor ();
320 pinyin_get_candidates (m_instance, lookup_cursor, m_candidates);
322 /* show guessed sentence only when m_candidates are available. */
323 if (m_candidates->len)
324 g_array_insert_val(m_candidates, 0, null_token);
326 updateLookupTable ();
327 updatePreeditText ();
328 updateAuxiliaryText ();
332 LibPinyinPhoneticEditor::commit (const gchar *str)
334 StaticText text(str);
339 LibPinyinPhoneticEditor::getPinyinCursor ()
341 /* Translate cursor position to pinyin position. */
342 PinyinKeyPosVector & pinyin_poses = m_instance->m_pinyin_key_rests;
343 guint pinyin_cursor = pinyin_poses->len;
344 for (size_t i = 0; i < pinyin_poses->len; ++i) {
345 PinyinKeyPos *pos = &g_array_index
346 (pinyin_poses, PinyinKeyPos, i);
347 if (pos->m_raw_begin <= m_cursor && m_cursor < pos->m_raw_end)
351 g_assert (pinyin_cursor >= 0);
352 return pinyin_cursor;
356 LibPinyinPhoneticEditor::getLookupCursor (void)
358 PinyinKeyVector & pinyins = m_instance->m_pinyin_keys;
359 guint lookup_cursor = getPinyinCursor ();
360 /* show candidates when pinyin cursor is at end. */
361 if (lookup_cursor == pinyins->len && m_pinyin_len == m_text.length())
363 return lookup_cursor;
367 LibPinyinPhoneticEditor::selectCandidate (guint i)
370 if (G_UNLIKELY (i >= m_candidates->len))
373 guint lookup_cursor = getLookupCursor ();
375 /* NOTE: deal with normal candidates selection here by libpinyin. */
376 phrase_token_t *token = &g_array_index (m_candidates, phrase_token_t, i);
377 if (null_token == *token) {
382 lookup_cursor = pinyin_choose_candidate (m_instance, lookup_cursor, *token);
383 pinyin_guess_sentence (m_instance);
385 PinyinKeyPosVector & pinyin_poses = m_instance->m_pinyin_key_rests;
386 if (lookup_cursor == pinyin_poses->len) {
390 PinyinKeyPos *pos = &g_array_index
391 (pinyin_poses, PinyinKeyPos, lookup_cursor);
392 m_cursor = pos->m_raw_begin;
398 LibPinyinPhoneticEditor::selectCandidateInPage (guint i)
400 guint page_size = m_lookup_table.pageSize ();
401 guint cursor_pos = m_lookup_table.cursorPos ();
403 if (G_UNLIKELY (i >= page_size))
405 i += (cursor_pos / page_size) * page_size;
407 return selectCandidate (i);
411 LibPinyinPhoneticEditor::removeCharBefore (void)
413 if (G_UNLIKELY (m_cursor == 0))
417 m_text.erase (m_cursor, 1);
426 LibPinyinPhoneticEditor::removeCharAfter (void)
428 if (G_UNLIKELY (m_cursor == m_text.length ()))
431 m_text.erase (m_cursor, 1);
440 LibPinyinPhoneticEditor::moveCursorLeft (void)
442 if (G_UNLIKELY (m_cursor == 0))
451 LibPinyinPhoneticEditor::moveCursorRight (void)
453 if (G_UNLIKELY (m_cursor == m_text.length ()))
462 LibPinyinPhoneticEditor::moveCursorToBegin (void)
464 if (G_UNLIKELY (m_cursor == 0))
473 LibPinyinPhoneticEditor::moveCursorToEnd (void)
475 if (G_UNLIKELY (m_cursor == m_text.length ()))
478 m_cursor = m_text.length ();
484 /* move cursor by word functions */
487 LibPinyinPhoneticEditor::getCursorLeftByWord (void)
491 if (G_UNLIKELY (m_cursor > m_pinyin_len)) {
492 cursor = m_pinyin_len;
494 PinyinKeyPosVector & pinyin_poses = m_instance->m_pinyin_key_rests;
495 guint pinyin_cursor = getPinyinCursor ();
496 PinyinKeyPos *pos = &g_array_index
497 (pinyin_poses, PinyinKeyPos, pinyin_cursor);
498 cursor = pos->m_raw_begin;
500 /* cursor at the begin of one pinyin */
501 g_return_val_if_fail (pinyin_cursor > 0, 0);
502 if ( cursor == m_cursor) {
504 (pinyin_poses, PinyinKeyPos, pinyin_cursor - 1);
505 cursor = pos->m_raw_begin;
513 LibPinyinPhoneticEditor::getCursorRightByWord (void)
517 if (G_UNLIKELY (m_cursor > m_pinyin_len)) {
518 cursor = m_text.length ();
520 guint pinyin_cursor = getPinyinCursor ();
521 PinyinKeyPos *pos = &g_array_index
522 (m_instance->m_pinyin_key_rests, PinyinKeyPos, pinyin_cursor);
523 cursor = pos->m_raw_end;
530 LibPinyinPhoneticEditor::removeWordBefore (void)
532 if (G_UNLIKELY (m_cursor == 0))
535 guint cursor = getCursorLeftByWord ();
536 m_text.erase (cursor, m_cursor - cursor);
544 LibPinyinPhoneticEditor::removeWordAfter (void)
546 if (G_UNLIKELY (m_cursor == m_text.length ()))
549 guint cursor = getCursorRightByWord ();
550 m_text.erase (m_cursor, cursor - m_cursor);
557 LibPinyinPhoneticEditor::moveCursorLeftByWord (void)
559 if (G_UNLIKELY (m_cursor == 0))
562 guint cursor = getCursorLeftByWord ();
570 LibPinyinPhoneticEditor::moveCursorRightByWord (void)
572 if (G_UNLIKELY (m_cursor == m_text.length ()))
575 guint cursor = getCursorRightByWord ();