[ibus-pinyin] add integration patch

Peng Wu pwu at fedoraproject.org
Thu Oct 27 04:47:37 UTC 2011


commit 1cc5988ae82a47995b7baf96ce5502b33e1f30a4
Author: Peng Wu <alexepico at gmail.com>
Date:   Thu Oct 27 12:47:21 2011 +0800

    add integration patch

 ibus-pinyin-libpinyin-integration.patch | 9524 +++++++++++++++++++++++++++++++
 ibus-pinyin-xx-icon-symbol.patch        |   24 +-
 ibus-pinyin.spec                        |    7 +-
 3 files changed, 9531 insertions(+), 24 deletions(-)
---
diff --git a/ibus-pinyin-libpinyin-integration.patch b/ibus-pinyin-libpinyin-integration.patch
new file mode 100644
index 0000000..d609be5
--- /dev/null
+++ b/ibus-pinyin-libpinyin-integration.patch
@@ -0,0 +1,9524 @@
+From 94bbc5c2f29f2d1e73c202dee9ca30b8ddc01c21 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Mon, 29 Aug 2011 14:14:46 +0800
+Subject: [PATCH 01/71] begin to integrate
+
+---
+ src/PYPinyinBaseEditor.h |   91 ++++++++++++++++++++++++++++++++++++++++++++++
+ 1 files changed, 91 insertions(+), 0 deletions(-)
+ create mode 100644 src/PYPinyinBaseEditor.h
+
+diff --git a/src/PYPinyinBaseEditor.h b/src/PYPinyinBaseEditor.h
+new file mode 100644
+index 0000000..0bed00a
+--- /dev/null
++++ b/src/PYPinyinBaseEditor.h
+@@ -0,0 +1,91 @@
++/* vim:set et ts=4 sts=4:
++ *
++ * ibus-pinyin - The Chinese PinYin engine for IBus
++ *
++ * Copyright (c) 2011 Peng Wu <alexepico at gmail.com>
++ *
++ * 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.
++ */
++#ifndef __PY_PINYIN_BASE_EDITOR_H_
++#define __PY_PINYIN_BASE_EDITOR_H_
++
++#include <libpinyin.h>
++#include "PYLookupTable.h"
++#include "PYEditor.h"
++#include "PYPinyinParser.h"
++#include "PYSpecialPhraseTable.h"
++
++namespace PY {
++
++class PinyinBaseEditor : public Editor {
++public:
++    PinyinBaseEditor (PinyinProperties & props, Config & config);
++
++public:
++    /* virtual functions */
++    virtual void pageUp (void);
++    virtual void pageDown (void);
++    virtual void cursorUp (void);
++    virtual void cursorDown (void);
++    virtual void update (void);
++    virtual void reset (void);
++    virtual void candidateClicked (guint index, guint button, guint state);
++    virtual gboolean processKeyEvent (guint keyval, guint keycode, guint modifiers);
++    virtual gboolean processSpace (guint keyval, guint keycode, guint modifiers);
++    virtual gboolean processFunctionKey (guint keyval, guint keycode, guint modifiers);
++    virtual void updateLookupTable ();
++    virtual void updateLookupTableFast ();
++    virtual gboolean fillLookupTableByPage ();
++
++protected:
++
++    gboolean updateSpecialPhrases ();
++    gboolean selectCandidate (guint i);
++    gboolean selectCandidateInPage (guint i);
++    gboolean resetCandidate (guint i);
++    gboolean resetCandidateInPage(guint i);
++
++    void commit (const gchar *str);
++
++    /* inline functions */
++
++    /* pure virtual functions */
++    virtual gboolean insert (gint ch) = 0;
++    virtual gboolean removeCharBefore (void) = 0;
++    virtual gboolean removeCharAfter (void) = 0;
++    virtual gboolean removeWordBefore (void) = 0;
++    virtual gboolean removeWordAfter (void) = 0;
++    virtual gboolean moveCursorLeft (void) = 0;
++    virtual gboolean moveCursorRight (void) = 0;
++    virtual gboolean moveCursorLeftByWord (void) = 0;
++    virtual gboolean moveCursorRightByWord (void) = 0;
++    virtual gboolean moveCursorToBegin (void) = 0;
++    virtual gboolean moveCursorToEnd (void) = 0;
++    virtual void commit (void) = 0;
++    virtual void updateAuxiliaryText (void) = 0;
++    virtual void updatePreeditText (void) = 0;
++
++    /* varibles */
++    PinyinArray                 m_pinyin;
++    guint                       m_pinyin_len;
++    LookupTable                 m_lookup_table;
++    /* libpinyin singleton here. */
++    std::vector<std::string>    m_special_phrases;
++    std::string                 m_selected_special_phrase;
++};
++
++};
++
++#endif
+-- 
+1.7.6.4
+
+
+From 21ee5c23e325fd7b4816b38b9cc308e17e23c1a3 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Tue, 30 Aug 2011 18:24:02 +0800
+Subject: [PATCH 02/71] begin to write libpinyin backend singleton
+
+---
+ src/PYLibPinyin.h |   36 ++++++++++++++++++++++++++++++++++++
+ 1 files changed, 36 insertions(+), 0 deletions(-)
+ create mode 100644 src/PYLibPinyin.h
+
+diff --git a/src/PYLibPinyin.h b/src/PYLibPinyin.h
+new file mode 100644
+index 0000000..cfd8566
+--- /dev/null
++++ b/src/PYLibPinyin.h
+@@ -0,0 +1,36 @@
++/* vim:set et ts=4 sts=4:
++ *
++ * ibus-pinyin - The Chinese PinYin engine for IBus
++ *
++ * Copyright (c) 2011 Peng Wu <alexepico at gmail.com>
++ *
++ * 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.
++ */
++
++#ifndef __PY_LIB_PINYIN_H_
++#define __PY_LIB_PINYIN_H_
++
++namespace PY {
++class LibPinyinBackEnd{
++public:
++    /* use static initializer in C++. */
++    static LibPinyinBackEnd & instance (void) { return *m_instance; }
++
++private:
++    static std::unique_ptr<LibPinyinBackEnd> m_instance;
++};
++};
++
++#endif
+-- 
+1.7.6.4
+
+
+From 71e25b32ed628a4692c43b48fa6a150884b05378 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Thu, 1 Sep 2011 11:24:02 +0800
+Subject: [PATCH 03/71] rename editor class
+
+---
+ src/PYLibPinyin.h        |    5 +++++
+ src/PYPinyinBaseEditor.h |   11 ++++++-----
+ 2 files changed, 11 insertions(+), 5 deletions(-)
+
+diff --git a/src/PYLibPinyin.h b/src/PYLibPinyin.h
+index cfd8566..d3bc90c 100644
+--- a/src/PYLibPinyin.h
++++ b/src/PYLibPinyin.h
+@@ -22,6 +22,8 @@
+ #ifndef __PY_LIB_PINYIN_H_
+ #define __PY_LIB_PINYIN_H_
+ 
++typedef struct _pinyin_context_t pinyin_context_t;
++
+ namespace PY {
+ class LibPinyinBackEnd{
+ public:
+@@ -29,6 +31,9 @@ public:
+     static LibPinyinBackEnd & instance (void) { return *m_instance; }
+ 
+ private:
++    pinyin_context_t *m_pinyin_context; /* libpinyin context */
++
++private:
+     static std::unique_ptr<LibPinyinBackEnd> m_instance;
+ };
+ };
+diff --git a/src/PYPinyinBaseEditor.h b/src/PYPinyinBaseEditor.h
+index 0bed00a..ee200a1 100644
+--- a/src/PYPinyinBaseEditor.h
++++ b/src/PYPinyinBaseEditor.h
+@@ -18,8 +18,8 @@
+  * along with this program; if not, write to the Free Software
+  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+  */
+-#ifndef __PY_PINYIN_BASE_EDITOR_H_
+-#define __PY_PINYIN_BASE_EDITOR_H_
++#ifndef __PY_LIB_PINYIN_BASE_EDITOR_H_
++#define __PY_LIB_PINYIN_BASE_EDITOR_H_
+ 
+ #include <libpinyin.h>
+ #include "PYLookupTable.h"
+@@ -29,9 +29,9 @@
+ 
+ namespace PY {
+ 
+-class PinyinBaseEditor : public Editor {
++class LibPinyinBaseEditor : public Editor {
+ public:
+-    PinyinBaseEditor (PinyinProperties & props, Config & config);
++    LibPinyinBaseEditor (PinyinProperties & props, Config & config);
+ 
+ public:
+     /* virtual functions */
+@@ -81,7 +81,8 @@ protected:
+     PinyinArray                 m_pinyin;
+     guint                       m_pinyin_len;
+     LookupTable                 m_lookup_table;
+-    /* libpinyin singleton here. */
++
++    /* use LibPinyinBackEnd here. */
+     std::vector<std::string>    m_special_phrases;
+     std::string                 m_selected_special_phrase;
+ };
+-- 
+1.7.6.4
+
+
+From b89b25c7c5522b25f4f8a023fea7bf73bb15db68 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Thu, 1 Sep 2011 13:02:24 +0800
+Subject: [PATCH 04/71] rename editor header
+
+---
+ src/PYLibPinyinBaseEditor.h |   92 +++++++++++++++++++++++++++++++++++++++++++
+ src/PYPinyinBaseEditor.h    |   92 -------------------------------------------
+ 2 files changed, 92 insertions(+), 92 deletions(-)
+ create mode 100644 src/PYLibPinyinBaseEditor.h
+ delete mode 100644 src/PYPinyinBaseEditor.h
+
+diff --git a/src/PYLibPinyinBaseEditor.h b/src/PYLibPinyinBaseEditor.h
+new file mode 100644
+index 0000000..ee200a1
+--- /dev/null
++++ b/src/PYLibPinyinBaseEditor.h
+@@ -0,0 +1,92 @@
++/* vim:set et ts=4 sts=4:
++ *
++ * ibus-pinyin - The Chinese PinYin engine for IBus
++ *
++ * Copyright (c) 2011 Peng Wu <alexepico at gmail.com>
++ *
++ * 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.
++ */
++#ifndef __PY_LIB_PINYIN_BASE_EDITOR_H_
++#define __PY_LIB_PINYIN_BASE_EDITOR_H_
++
++#include <libpinyin.h>
++#include "PYLookupTable.h"
++#include "PYEditor.h"
++#include "PYPinyinParser.h"
++#include "PYSpecialPhraseTable.h"
++
++namespace PY {
++
++class LibPinyinBaseEditor : public Editor {
++public:
++    LibPinyinBaseEditor (PinyinProperties & props, Config & config);
++
++public:
++    /* virtual functions */
++    virtual void pageUp (void);
++    virtual void pageDown (void);
++    virtual void cursorUp (void);
++    virtual void cursorDown (void);
++    virtual void update (void);
++    virtual void reset (void);
++    virtual void candidateClicked (guint index, guint button, guint state);
++    virtual gboolean processKeyEvent (guint keyval, guint keycode, guint modifiers);
++    virtual gboolean processSpace (guint keyval, guint keycode, guint modifiers);
++    virtual gboolean processFunctionKey (guint keyval, guint keycode, guint modifiers);
++    virtual void updateLookupTable ();
++    virtual void updateLookupTableFast ();
++    virtual gboolean fillLookupTableByPage ();
++
++protected:
++
++    gboolean updateSpecialPhrases ();
++    gboolean selectCandidate (guint i);
++    gboolean selectCandidateInPage (guint i);
++    gboolean resetCandidate (guint i);
++    gboolean resetCandidateInPage(guint i);
++
++    void commit (const gchar *str);
++
++    /* inline functions */
++
++    /* pure virtual functions */
++    virtual gboolean insert (gint ch) = 0;
++    virtual gboolean removeCharBefore (void) = 0;
++    virtual gboolean removeCharAfter (void) = 0;
++    virtual gboolean removeWordBefore (void) = 0;
++    virtual gboolean removeWordAfter (void) = 0;
++    virtual gboolean moveCursorLeft (void) = 0;
++    virtual gboolean moveCursorRight (void) = 0;
++    virtual gboolean moveCursorLeftByWord (void) = 0;
++    virtual gboolean moveCursorRightByWord (void) = 0;
++    virtual gboolean moveCursorToBegin (void) = 0;
++    virtual gboolean moveCursorToEnd (void) = 0;
++    virtual void commit (void) = 0;
++    virtual void updateAuxiliaryText (void) = 0;
++    virtual void updatePreeditText (void) = 0;
++
++    /* varibles */
++    PinyinArray                 m_pinyin;
++    guint                       m_pinyin_len;
++    LookupTable                 m_lookup_table;
++
++    /* use LibPinyinBackEnd here. */
++    std::vector<std::string>    m_special_phrases;
++    std::string                 m_selected_special_phrase;
++};
++
++};
++
++#endif
+diff --git a/src/PYPinyinBaseEditor.h b/src/PYPinyinBaseEditor.h
+deleted file mode 100644
+index ee200a1..0000000
+--- a/src/PYPinyinBaseEditor.h
++++ /dev/null
+@@ -1,92 +0,0 @@
+-/* vim:set et ts=4 sts=4:
+- *
+- * ibus-pinyin - The Chinese PinYin engine for IBus
+- *
+- * Copyright (c) 2011 Peng Wu <alexepico at gmail.com>
+- *
+- * 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.
+- */
+-#ifndef __PY_LIB_PINYIN_BASE_EDITOR_H_
+-#define __PY_LIB_PINYIN_BASE_EDITOR_H_
+-
+-#include <libpinyin.h>
+-#include "PYLookupTable.h"
+-#include "PYEditor.h"
+-#include "PYPinyinParser.h"
+-#include "PYSpecialPhraseTable.h"
+-
+-namespace PY {
+-
+-class LibPinyinBaseEditor : public Editor {
+-public:
+-    LibPinyinBaseEditor (PinyinProperties & props, Config & config);
+-
+-public:
+-    /* virtual functions */
+-    virtual void pageUp (void);
+-    virtual void pageDown (void);
+-    virtual void cursorUp (void);
+-    virtual void cursorDown (void);
+-    virtual void update (void);
+-    virtual void reset (void);
+-    virtual void candidateClicked (guint index, guint button, guint state);
+-    virtual gboolean processKeyEvent (guint keyval, guint keycode, guint modifiers);
+-    virtual gboolean processSpace (guint keyval, guint keycode, guint modifiers);
+-    virtual gboolean processFunctionKey (guint keyval, guint keycode, guint modifiers);
+-    virtual void updateLookupTable ();
+-    virtual void updateLookupTableFast ();
+-    virtual gboolean fillLookupTableByPage ();
+-
+-protected:
+-
+-    gboolean updateSpecialPhrases ();
+-    gboolean selectCandidate (guint i);
+-    gboolean selectCandidateInPage (guint i);
+-    gboolean resetCandidate (guint i);
+-    gboolean resetCandidateInPage(guint i);
+-
+-    void commit (const gchar *str);
+-
+-    /* inline functions */
+-
+-    /* pure virtual functions */
+-    virtual gboolean insert (gint ch) = 0;
+-    virtual gboolean removeCharBefore (void) = 0;
+-    virtual gboolean removeCharAfter (void) = 0;
+-    virtual gboolean removeWordBefore (void) = 0;
+-    virtual gboolean removeWordAfter (void) = 0;
+-    virtual gboolean moveCursorLeft (void) = 0;
+-    virtual gboolean moveCursorRight (void) = 0;
+-    virtual gboolean moveCursorLeftByWord (void) = 0;
+-    virtual gboolean moveCursorRightByWord (void) = 0;
+-    virtual gboolean moveCursorToBegin (void) = 0;
+-    virtual gboolean moveCursorToEnd (void) = 0;
+-    virtual void commit (void) = 0;
+-    virtual void updateAuxiliaryText (void) = 0;
+-    virtual void updatePreeditText (void) = 0;
+-
+-    /* varibles */
+-    PinyinArray                 m_pinyin;
+-    guint                       m_pinyin_len;
+-    LookupTable                 m_lookup_table;
+-
+-    /* use LibPinyinBackEnd here. */
+-    std::vector<std::string>    m_special_phrases;
+-    std::string                 m_selected_special_phrase;
+-};
+-
+-};
+-
+-#endif
+-- 
+1.7.6.4
+
+
+From 9103387c14422521f7449806079bf411ab8f6fd3 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Thu, 1 Sep 2011 15:13:09 +0800
+Subject: [PATCH 05/71] begin to write libpinyin base editor
+
+---
+ src/PYLibPinyinBaseEditor.cc |  318 ++++++++++++++++++++++++++++++++++++++++++
+ src/PYLibPinyinBaseEditor.h  |    2 -
+ 2 files changed, 318 insertions(+), 2 deletions(-)
+ create mode 100644 src/PYLibPinyinBaseEditor.cc
+
+diff --git a/src/PYLibPinyinBaseEditor.cc b/src/PYLibPinyinBaseEditor.cc
+new file mode 100644
+index 0000000..81ef1f2
+--- /dev/null
++++ b/src/PYLibPinyinBaseEditor.cc
+@@ -0,0 +1,318 @@
++/* vim:set et ts=4 sts=4:
++ *
++ * ibus-pinyin - The Chinese PinYin engine for IBus
++ *
++ * Copyright (c) 2011 Peng Wu <alexepico at gmail.com>
++ *
++ * 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 "PYLibPinyinBaseEditor.h"
++#include "PYConfig.h"
++#include "PYPinyinProperties.h"
++#include "PYSimpTradConverter.h"
++
++namespace PY {
++/* init static members */
++LibPinyinBaseEditor::LibPinyinBaseEditor (PinyinProperties &props,
++                                          Config &config):
++    Editor (props, config),
++    m_pinyin (MAX_PHRASE_LEN),
++    m_pinyin_len (0),
++    m_lookup_table (m_config.pageSize ())
++{
++}
++
++gboolean
++LibPinyinBaseEditor::processSpace (guint keyval, guint keycode,
++                                   guint modifiers)
++{
++    if (!m_text)
++        return FALSE;
++    if (cmshm_filter (modifiers) != 0)
++        return TRUE;
++    if (m_lookup_table.size () != 0) {
++        selectCandidate (m_lookup_table.cursorPos ());
++    } else {
++        commit ();
++    }
++    return TRUE;
++}
++
++gboolean
++LibPinyinBaseEditor::processFunctionKey (guint keyval, guint keycode, guint modifiers)
++{
++    if (m_text.empty ())
++        return FALSE;
++
++    /* ignore numlock */
++    modifiers = cmshm_filter (modifiers);
++
++    if (modifiers != 0 && modifiers != IBUS_CONTROL_MASK)
++        return TRUE;
++
++    /* process some cursor control keys */
++    if (modifiers == 0) {  /* no modifiers. */
++        switch (keyval) {
++        case IBUS_Return:
++        case IBUS_KP_Enter:
++            commit ();
++            return TRUE;
++
++        case IBUS_BackSpace:
++            removeCharBefore ();
++            return TRUE;
++
++        case IBUS_Delete:
++        case IBUS_KP_Delete:
++            removeCharAfter ();
++            return TRUE;
++
++        case IBUS_Left:
++        case IBUS_KP_Left:
++            moveCursorLeft ();
++            return TRUE;
++
++        case IBUS_Right:
++        case IBUS_KP_Right:
++            moveCursorRight ();
++            return TRUE;
++
++        case IBUS_Home:
++        case IBUS_KP_Home:
++            moveCursorToBegin ();
++            return TRUE;
++
++        case IBUS_End:
++        case IBUS_KP_End:
++            moveCursorToEnd ();
++            return TRUE;
++
++        case IBUS_Up:
++        case IBUS_KP_Up:
++            cursorUp ();
++            return TRUE;
++
++        case IBUS_Down:
++        case IBUS_KP_Down:
++            cursorDown ();
++            return TRUE;
++
++        case IBUS_Page_Up:
++        case IBUS_KP_Page_Up:
++            pageUp ();
++            return TRUE;
++
++        case IBUS_Page_Down:
++        case IBUS_KP_Page_Down:
++        case IBUS_Tab:
++            pageDown ();
++            return TRUE;
++
++        case IBUS_Escape:
++            reset ();
++            return TRUE;
++        default:
++            return TRUE;
++        }
++    } else { /* ctrl key pressed. */
++        switch (keyval) {
++        case IBUS_BackSpace:
++            removeWordBefore ();
++            return TRUE;
++
++        case IBUS_Delete:
++        case IBUS_KP_Delete:
++            removeWordAfter ();
++            return TRUE;
++
++        case IBUS_Left:
++        case IBUS_KP_Left:
++            moveCursorLeftByWord ();
++            return TRUE;
++
++        case IBUS_Right:
++        case IBUS_KP_Right:
++            moveCursorToEnd ();
++            return TRUE;
++
++        default:
++            return TRUE;
++        }
++    }
++    return TRUE;
++}
++
++gboolean
++LibPinyinBaseEditor::processKeyEvent (guint keyval, guint keycode, guint modifiers)
++{
++    return FALSE;
++}
++
++gboolean
++LibPinyinBaseEditor::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;
++
++    /* TODO: change behavior to match the entire m_text,
++     *         instead of partial of m_text.
++     */
++    g_assert(FALSE);
++}
++
++void
++LibPinyinBaseEditor::updateLookupTableFast (void)
++{
++    Editor::updateLookupTableFast (m_lookup_table, TRUE);
++}
++
++void
++LibPinyinBaseEditor::updateLookupTable (void)
++{
++    m_lookup_table.clear ();
++
++    fillLookupTableByPage ();
++    if (m_lookup_table.size()) {
++        Editor::updateLookupTable (m_lookup_table, TRUE);
++    } else {
++        hideLookupTable ();
++    }
++}
++
++gboolean
++LibPinyinBaseEditor::fillLookupTableByPage (void)
++{
++    if (!m_selected_special_phrase.empty ()) {
++        return FALSE;
++    }
++
++    guint filled_nr = m_lookup_table.size ();
++    guint page_size = m_lookup_table.pageSize ();
++
++    /* fill lookup table by libpinyin get candidates. */
++    g_assert(FALSE);
++}
++
++void
++LibPinyinBaseEditor::pageUp (void)
++{
++    if (G_LIKELY (m_lookup_table.pageUp ())) {
++        updateLookupTableFast ();
++        updatePreeditText ();
++        updateAuxiliaryText ();
++    }
++}
++
++void
++LibPinyinBaseEditor::pageDown (void)
++{
++    if (G_LIKELY((m_lookup_table.pageDown ()) ||
++                 (fillLookupTableByPage () && m_lookup_table.pageDown()))) {
++        updateLookupTableFast ();
++        updatePreeditText ();
++        updateAuxiliaryText ();
++    }
++}
++
++void
++LibPinyinBaseEditor::cursorUp (void)
++{
++    if (G_LIKELY (m_lookup_table.cursorUp ())) {
++        updateLookupTableFast ();
++        updatePreeditText ();
++        updateAuxiliaryText ();
++    }
++}
++
++void
++LibPinyinBaseEditor::cursorDown (void)
++{
++    if (G_LIKELY ((m_lookup_table.cursorPos () == m_lookup_table.size() - 1) &&
++                  (fillLookupTableByPage () == FALSE))) {
++        return;
++    }
++
++    if (G_LIKELY (m_lookup_table.cursorDown ())) {
++        updateLookupTableFast ();
++        updatePreeditText ();
++        updateAuxiliaryText ();
++    }
++}
++
++void
++LibPinyinBaseEditor::candidateClicked (guint index, guint button, guint state)
++{
++    selectCandidateInPage (index);
++}
++
++void
++LibPinyinBaseEditor::reset (void)
++{
++    m_pinyin.clear ();
++    m_pinyin_len = 0;
++    m_lookup_table.clear ();
++    m_special_phrases.clear ();
++    m_selected_special_phrase.clear ();
++
++    Editor::reset ();
++}
++
++void
++LibPinyinBaseEditor::update (void)
++{
++    updateLookupTable ();
++    updatePreeditText ();
++    updateAuxiliaryText ();
++}
++
++void
++LibPinyinBaseEditor::commit (const gchar *str)
++{
++    StaticText text(str);
++    commitText (text);
++}
++
++gboolean
++LibPinyinBaseEditor::selectCandidate (guint i)
++{
++    g_assert(FALSE);
++    if (i < m_special_phrases.size ()) {
++        /* select a special phrase */
++        m_selected_special_phrase = m_special_phrases[i];
++
++        /* refer to updateSpecialPhrases. */
++    }
++}
++
++gboolean
++LibPinyinBaseEditor::selectCandidateInPage (guint i)
++{
++    guint page_size = m_lookup_table.pageSize ();
++    guint cursor_pos = m_lookup_table.cursorPos ();
++
++    if (G_UNLIKELY (i >= page_size))
++        return FALSE;
++    i += (cursor_pos / page_size) * page_size;
++
++    return selectCandidate (i);
++}
++
++};
+diff --git a/src/PYLibPinyinBaseEditor.h b/src/PYLibPinyinBaseEditor.h
+index ee200a1..c7b0d2b 100644
+--- a/src/PYLibPinyinBaseEditor.h
++++ b/src/PYLibPinyinBaseEditor.h
+@@ -54,8 +54,6 @@ protected:
+     gboolean updateSpecialPhrases ();
+     gboolean selectCandidate (guint i);
+     gboolean selectCandidateInPage (guint i);
+-    gboolean resetCandidate (guint i);
+-    gboolean resetCandidateInPage(guint i);
+ 
+     void commit (const gchar *str);
+ 
+-- 
+1.7.6.4
+
+
+From 2f3696c5af718b4eeb6113dc0b68bd9525027ec2 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Thu, 1 Sep 2011 15:51:53 +0800
+Subject: [PATCH 06/71] fixes compile
+
+---
+ src/Makefile.am              |    3 +++
+ src/PYLibPinyinBaseEditor.cc |    1 -
+ src/PYLibPinyinBaseEditor.h  |    1 -
+ 3 files changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/src/Makefile.am b/src/Makefile.am
+index 2ca6c1e..a104c75 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -64,6 +64,7 @@ ibus_engine_pinyin_c_sources = \
+ 	PYDynamicSpecialPhrase.cc \
+ 	PYSpecialPhrase.cc \
+ 	PYSpecialPhraseTable.cc \
++	PYLibPinyinBaseEditor.cc \
+ 	$(NULL)
+ ibus_engine_pinyin_h_sources = \
+ 	PYBopomofo.h \
+@@ -106,6 +107,8 @@ ibus_engine_pinyin_h_sources = \
+ 	PYTypes.h \
+ 	PYUtil.h \
+ 	PYEnglishEditor.h \
++	PYLibPinyin.h \
++	PYLibPinyinBaseEditor.h \
+ 	$(NULL)
+ 
+ if IBUS_BUILD_LUA_EXTENSION
+diff --git a/src/PYLibPinyinBaseEditor.cc b/src/PYLibPinyinBaseEditor.cc
+index 81ef1f2..74acba4 100644
+--- a/src/PYLibPinyinBaseEditor.cc
++++ b/src/PYLibPinyinBaseEditor.cc
+@@ -163,7 +163,6 @@ LibPinyinBaseEditor::processKeyEvent (guint keyval, guint keycode, guint modifie
+ gboolean
+ LibPinyinBaseEditor::updateSpecialPhrases (void)
+ {
+-    guint size = m_special_phrases.size ();
+     m_special_phrases.clear ();
+ 
+     if (!m_config.specialPhrases ())
+diff --git a/src/PYLibPinyinBaseEditor.h b/src/PYLibPinyinBaseEditor.h
+index c7b0d2b..d682a7b 100644
+--- a/src/PYLibPinyinBaseEditor.h
++++ b/src/PYLibPinyinBaseEditor.h
+@@ -21,7 +21,6 @@
+ #ifndef __PY_LIB_PINYIN_BASE_EDITOR_H_
+ #define __PY_LIB_PINYIN_BASE_EDITOR_H_
+ 
+-#include <libpinyin.h>
+ #include "PYLookupTable.h"
+ #include "PYEditor.h"
+ #include "PYPinyinParser.h"
+-- 
+1.7.6.4
+
+
+From b6cc94ba4d65f1511aebb5b2da80c958cd882815 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Fri, 2 Sep 2011 10:34:06 +0800
+Subject: [PATCH 07/71] add special phrases handle in libpinyin base editor
+
+---
+ src/PYLibPinyinBaseEditor.cc |   27 +++++++++++++++++++++------
+ src/PYLibPinyinBaseEditor.h  |    1 +
+ 2 files changed, 22 insertions(+), 6 deletions(-)
+
+diff --git a/src/PYLibPinyinBaseEditor.cc b/src/PYLibPinyinBaseEditor.cc
+index 74acba4..6fdd5ef 100644
+--- a/src/PYLibPinyinBaseEditor.cc
++++ b/src/PYLibPinyinBaseEditor.cc
+@@ -163,6 +163,7 @@ LibPinyinBaseEditor::processKeyEvent (guint keyval, guint keycode, guint modifie
+ gboolean
+ LibPinyinBaseEditor::updateSpecialPhrases (void)
+ {
++    guint size = m_special_phrases.size();
+     m_special_phrases.clear ();
+ 
+     if (!m_config.specialPhrases ())
+@@ -171,10 +172,13 @@ LibPinyinBaseEditor::updateSpecialPhrases (void)
+     if (!m_selected_special_phrase.empty ())
+         return FALSE;
+ 
+-    /* TODO: change behavior to match the entire m_text,
+-     *         instead of partial of m_text.
++    /* Note: change behavior to match the entire m_text,
++     *         instead of partial m_text.
+      */
+-    g_assert(FALSE);
++    SpecialPhraseTable::instance ().lookup
++        (m_text, m_special_phrases);
++
++    return size != m_special_phrases.size() || size != 0;
+ }
+ 
+ void
+@@ -292,13 +296,24 @@ LibPinyinBaseEditor::commit (const gchar *str)
+ gboolean
+ LibPinyinBaseEditor::selectCandidate (guint i)
+ {
+-    g_assert(FALSE);
++
+     if (i < m_special_phrases.size ()) {
+         /* select a special phrase */
+         m_selected_special_phrase = m_special_phrases[i];
+-
+-        /* refer to updateSpecialPhrases. */
++        if (m_cursor == m_text.size()) {
++            m_buffer = m_selected_special_phrase;
++            reset ();
++            commit ((const gchar *)m_buffer);
++        } else {
++            updateSpecialPhrases ();
++            update ();
++        }
++        return TRUE;
+     }
++
++    i -= m_special_phrases.size ();
++    /* TODO: deal with normal candidates selection here by libpinyin. */
++    g_assert (FALSE);
+ }
+ 
+ gboolean
+diff --git a/src/PYLibPinyinBaseEditor.h b/src/PYLibPinyinBaseEditor.h
+index d682a7b..fa5755c 100644
+--- a/src/PYLibPinyinBaseEditor.h
++++ b/src/PYLibPinyinBaseEditor.h
+@@ -78,6 +78,7 @@ protected:
+     PinyinArray                 m_pinyin;
+     guint                       m_pinyin_len;
+     LookupTable                 m_lookup_table;
++    String                      m_buffer;
+ 
+     /* use LibPinyinBackEnd here. */
+     std::vector<std::string>    m_special_phrases;
+-- 
+1.7.6.4
+
+
+From 61aafedfb9cf7718afebb4cb8a3eb82873bafa1d Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Fri, 2 Sep 2011 14:30:11 +0800
+Subject: [PATCH 08/71] begin to write concrete pinyin editors
+
+---
+ src/PYLibPinyinDoublePinyinEditor.h |   57 +++++++++++++++++++++++++++++++++
+ src/PYLibPinyinFullPinyinEditor.h   |   59 +++++++++++++++++++++++++++++++++++
+ 2 files changed, 116 insertions(+), 0 deletions(-)
+ create mode 100644 src/PYLibPinyinDoublePinyinEditor.h
+ create mode 100644 src/PYLibPinyinFullPinyinEditor.h
+
+diff --git a/src/PYLibPinyinDoublePinyinEditor.h b/src/PYLibPinyinDoublePinyinEditor.h
+new file mode 100644
+index 0000000..5ed106f
+--- /dev/null
++++ b/src/PYLibPinyinDoublePinyinEditor.h
+@@ -0,0 +1,57 @@
++/* vim:set et ts=4 sts=4:
++ *
++ * ibus-pinyin - The Chinese PinYin engine for IBus
++ *
++ * Copyright (c) 2011 Peng Wu <alexepico at gmail.com>
++ *
++ * 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.
++ */
++#ifndef __PY_LIB_PINYIN_DOUBLE_PINYIN_EDITOR_H_
++#define __PY_LIB_PINYIN_DOUBLE_PINYIN_EDITOR_H_
++
++#include "PYLibPinyinBaseEditor.h"
++
++namespace PY {
++
++class LibPinyinDoublePinyinEditor : public LibPinyinBaseEditor {
++
++public:
++    LibPinyinDoublePinyinEditor (PinyinProperties & props, Config & config);
++
++    gboolean insert (gint ch);
++
++    gboolean removeCharBefore (void);
++    gboolean removeCharAfter (void);
++    gboolean removeWordBefore (void);
++    gboolean removeWordAfter (void);
++
++    gboolean moveCursorLeft (void);
++    gboolean moveCursorRight (void);
++    gboolean moveCursorLeftByWord (void);
++    gboolean moveCursorRightByWord (void);
++    gboolean moveCursorToBegin (void);
++    gboolean moveCursorToEnd (void);
++
++    /* override virtual functions */
++    gboolean processKeyEvent (guint keyval, guint keycode, guint modifiers);
++    void reset (void);
++
++protected:
++    /* TODO: to be implemented. */
++};
++
++};
++
++#endif
+diff --git a/src/PYLibPinyinFullPinyinEditor.h b/src/PYLibPinyinFullPinyinEditor.h
+new file mode 100644
+index 0000000..dcc1728
+--- /dev/null
++++ b/src/PYLibPinyinFullPinyinEditor.h
+@@ -0,0 +1,59 @@
++/* vim:set et ts=4 sts=4:
++ *
++ * ibus-pinyin - The Chinese PinYin engine for IBus
++ *
++ * Copyright (c) 2011 Peng Wu <alexepico at gmail.com>
++ *
++ * 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.
++ */
++#ifndef __PY_LIB_PINYIN_FULL_PINYIN_EDITOR_H
++#define __PY_LIB_PINYIN_FULL_PINYIN_EDITOR_H
++
++#include "PYLibPinyinBaseEditor.h"
++
++namespace PY {
++
++class LibPinyinFullPinyinEditor : public PinyinEditor {
++
++public:
++    LibPinyinFullPinyinEditor (PinyinProperties & props, Config & config);
++    ~LibPinyinFullPinyinEditor (void);
++
++public:
++    gboolean insert (gint ch);
++
++    gboolean removeCharBefore (void);
++    gboolean removeCharAfter (void);
++    gboolean removeWordBefore (void);
++    gboolean removeWordAfter (void);
++
++    gboolean moveCursorLeft (void);
++    gboolean moveCursorRight (void);
++    gboolean moveCursorLeftByWord (void);
++    gboolean moveCursorRightByWord (void);
++    gboolean moveCursorToBegin (void);
++    gboolean moveCursorToEnd (void);
++
++    /* virtual functions */
++    virtual gboolean processKeyEvent (guint keyval, guint keycode, guint modifiers);
++    virtual void reset (void);
++
++protected:
++    /* TODO: to be implemented. */
++};
++
++};
++
++#endif
+-- 
+1.7.6.4
+
+
+From 56d08018ceb62e0dfaff14cc3456e7b1e65dc53b Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Fri, 2 Sep 2011 15:26:21 +0800
+Subject: [PATCH 09/71] rename files
+
+---
+ src/PYLibPinyinBaseEditor.cc        |  332 -----------------------------------
+ src/PYLibPinyinBaseEditor.h         |   90 ----------
+ src/PYLibPinyinDoublePinyinEditor.h |   57 ------
+ src/PYLibPinyinFullPinyinEditor.h   |   59 ------
+ src/PYPDoublePinyinEditor.h         |   57 ++++++
+ src/PYPFullPinyinEditor.h           |   59 ++++++
+ src/PYPPhoneticEditor.cc            |  332 +++++++++++++++++++++++++++++++++++
+ src/PYPPhoneticEditor.h             |   90 ++++++++++
+ 8 files changed, 538 insertions(+), 538 deletions(-)
+ delete mode 100644 src/PYLibPinyinBaseEditor.cc
+ delete mode 100644 src/PYLibPinyinBaseEditor.h
+ delete mode 100644 src/PYLibPinyinDoublePinyinEditor.h
+ delete mode 100644 src/PYLibPinyinFullPinyinEditor.h
+ create mode 100644 src/PYPDoublePinyinEditor.h
+ create mode 100644 src/PYPFullPinyinEditor.h
+ create mode 100644 src/PYPPhoneticEditor.cc
+ create mode 100644 src/PYPPhoneticEditor.h
+
+diff --git a/src/PYLibPinyinBaseEditor.cc b/src/PYLibPinyinBaseEditor.cc
+deleted file mode 100644
+index 6fdd5ef..0000000
+--- a/src/PYLibPinyinBaseEditor.cc
++++ /dev/null
+@@ -1,332 +0,0 @@
+-/* vim:set et ts=4 sts=4:
+- *
+- * ibus-pinyin - The Chinese PinYin engine for IBus
+- *
+- * Copyright (c) 2011 Peng Wu <alexepico at gmail.com>
+- *
+- * 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 "PYLibPinyinBaseEditor.h"
+-#include "PYConfig.h"
+-#include "PYPinyinProperties.h"
+-#include "PYSimpTradConverter.h"
+-
+-namespace PY {
+-/* init static members */
+-LibPinyinBaseEditor::LibPinyinBaseEditor (PinyinProperties &props,
+-                                          Config &config):
+-    Editor (props, config),
+-    m_pinyin (MAX_PHRASE_LEN),
+-    m_pinyin_len (0),
+-    m_lookup_table (m_config.pageSize ())
+-{
+-}
+-
+-gboolean
+-LibPinyinBaseEditor::processSpace (guint keyval, guint keycode,
+-                                   guint modifiers)
+-{
+-    if (!m_text)
+-        return FALSE;
+-    if (cmshm_filter (modifiers) != 0)
+-        return TRUE;
+-    if (m_lookup_table.size () != 0) {
+-        selectCandidate (m_lookup_table.cursorPos ());
+-    } else {
+-        commit ();
+-    }
+-    return TRUE;
+-}
+-
+-gboolean
+-LibPinyinBaseEditor::processFunctionKey (guint keyval, guint keycode, guint modifiers)
+-{
+-    if (m_text.empty ())
+-        return FALSE;
+-
+-    /* ignore numlock */
+-    modifiers = cmshm_filter (modifiers);
+-
+-    if (modifiers != 0 && modifiers != IBUS_CONTROL_MASK)
+-        return TRUE;
+-
+-    /* process some cursor control keys */
+-    if (modifiers == 0) {  /* no modifiers. */
+-        switch (keyval) {
+-        case IBUS_Return:
+-        case IBUS_KP_Enter:
+-            commit ();
+-            return TRUE;
+-
+-        case IBUS_BackSpace:
+-            removeCharBefore ();
+-            return TRUE;
+-
+-        case IBUS_Delete:
+-        case IBUS_KP_Delete:
+-            removeCharAfter ();
+-            return TRUE;
+-
+-        case IBUS_Left:
+-        case IBUS_KP_Left:
+-            moveCursorLeft ();
+-            return TRUE;
+-
+-        case IBUS_Right:
+-        case IBUS_KP_Right:
+-            moveCursorRight ();
+-            return TRUE;
+-
+-        case IBUS_Home:
+-        case IBUS_KP_Home:
+-            moveCursorToBegin ();
+-            return TRUE;
+-
+-        case IBUS_End:
+-        case IBUS_KP_End:
+-            moveCursorToEnd ();
+-            return TRUE;
+-
+-        case IBUS_Up:
+-        case IBUS_KP_Up:
+-            cursorUp ();
+-            return TRUE;
+-
+-        case IBUS_Down:
+-        case IBUS_KP_Down:
+-            cursorDown ();
+-            return TRUE;
+-
+-        case IBUS_Page_Up:
+-        case IBUS_KP_Page_Up:
+-            pageUp ();
+-            return TRUE;
+-
+-        case IBUS_Page_Down:
+-        case IBUS_KP_Page_Down:
+-        case IBUS_Tab:
+-            pageDown ();
+-            return TRUE;
+-
+-        case IBUS_Escape:
+-            reset ();
+-            return TRUE;
+-        default:
+-            return TRUE;
+-        }
+-    } else { /* ctrl key pressed. */
+-        switch (keyval) {
+-        case IBUS_BackSpace:
+-            removeWordBefore ();
+-            return TRUE;
+-
+-        case IBUS_Delete:
+-        case IBUS_KP_Delete:
+-            removeWordAfter ();
+-            return TRUE;
+-
+-        case IBUS_Left:
+-        case IBUS_KP_Left:
+-            moveCursorLeftByWord ();
+-            return TRUE;
+-
+-        case IBUS_Right:
+-        case IBUS_KP_Right:
+-            moveCursorToEnd ();
+-            return TRUE;
+-
+-        default:
+-            return TRUE;
+-        }
+-    }
+-    return TRUE;
+-}
+-
+-gboolean
+-LibPinyinBaseEditor::processKeyEvent (guint keyval, guint keycode, guint modifiers)
+-{
+-    return FALSE;
+-}
+-
+-gboolean
+-LibPinyinBaseEditor::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;
+-
+-    /* Note: change behavior to match the entire m_text,
+-     *         instead of partial m_text.
+-     */
+-    SpecialPhraseTable::instance ().lookup
+-        (m_text, m_special_phrases);
+-
+-    return size != m_special_phrases.size() || size != 0;
+-}
+-
+-void
+-LibPinyinBaseEditor::updateLookupTableFast (void)
+-{
+-    Editor::updateLookupTableFast (m_lookup_table, TRUE);
+-}
+-
+-void
+-LibPinyinBaseEditor::updateLookupTable (void)
+-{
+-    m_lookup_table.clear ();
+-
+-    fillLookupTableByPage ();
+-    if (m_lookup_table.size()) {
+-        Editor::updateLookupTable (m_lookup_table, TRUE);
+-    } else {
+-        hideLookupTable ();
+-    }
+-}
+-
+-gboolean
+-LibPinyinBaseEditor::fillLookupTableByPage (void)
+-{
+-    if (!m_selected_special_phrase.empty ()) {
+-        return FALSE;
+-    }
+-
+-    guint filled_nr = m_lookup_table.size ();
+-    guint page_size = m_lookup_table.pageSize ();
+-
+-    /* fill lookup table by libpinyin get candidates. */
+-    g_assert(FALSE);
+-}
+-
+-void
+-LibPinyinBaseEditor::pageUp (void)
+-{
+-    if (G_LIKELY (m_lookup_table.pageUp ())) {
+-        updateLookupTableFast ();
+-        updatePreeditText ();
+-        updateAuxiliaryText ();
+-    }
+-}
+-
+-void
+-LibPinyinBaseEditor::pageDown (void)
+-{
+-    if (G_LIKELY((m_lookup_table.pageDown ()) ||
+-                 (fillLookupTableByPage () && m_lookup_table.pageDown()))) {
+-        updateLookupTableFast ();
+-        updatePreeditText ();
+-        updateAuxiliaryText ();
+-    }
+-}
+-
+-void
+-LibPinyinBaseEditor::cursorUp (void)
+-{
+-    if (G_LIKELY (m_lookup_table.cursorUp ())) {
+-        updateLookupTableFast ();
+-        updatePreeditText ();
+-        updateAuxiliaryText ();
+-    }
+-}
+-
+-void
+-LibPinyinBaseEditor::cursorDown (void)
+-{
+-    if (G_LIKELY ((m_lookup_table.cursorPos () == m_lookup_table.size() - 1) &&
+-                  (fillLookupTableByPage () == FALSE))) {
+-        return;
+-    }
+-
+-    if (G_LIKELY (m_lookup_table.cursorDown ())) {
+-        updateLookupTableFast ();
+-        updatePreeditText ();
+-        updateAuxiliaryText ();
+-    }
+-}
+-
+-void
+-LibPinyinBaseEditor::candidateClicked (guint index, guint button, guint state)
+-{
+-    selectCandidateInPage (index);
+-}
+-
+-void
+-LibPinyinBaseEditor::reset (void)
+-{
+-    m_pinyin.clear ();
+-    m_pinyin_len = 0;
+-    m_lookup_table.clear ();
+-    m_special_phrases.clear ();
+-    m_selected_special_phrase.clear ();
+-
+-    Editor::reset ();
+-}
+-
+-void
+-LibPinyinBaseEditor::update (void)
+-{
+-    updateLookupTable ();
+-    updatePreeditText ();
+-    updateAuxiliaryText ();
+-}
+-
+-void
+-LibPinyinBaseEditor::commit (const gchar *str)
+-{
+-    StaticText text(str);
+-    commitText (text);
+-}
+-
+-gboolean
+-LibPinyinBaseEditor::selectCandidate (guint i)
+-{
+-
+-    if (i < m_special_phrases.size ()) {
+-        /* select a special phrase */
+-        m_selected_special_phrase = m_special_phrases[i];
+-        if (m_cursor == m_text.size()) {
+-            m_buffer = m_selected_special_phrase;
+-            reset ();
+-            commit ((const gchar *)m_buffer);
+-        } else {
+-            updateSpecialPhrases ();
+-            update ();
+-        }
+-        return TRUE;
+-    }
+-
+-    i -= m_special_phrases.size ();
+-    /* TODO: deal with normal candidates selection here by libpinyin. */
+-    g_assert (FALSE);
+-}
+-
+-gboolean
+-LibPinyinBaseEditor::selectCandidateInPage (guint i)
+-{
+-    guint page_size = m_lookup_table.pageSize ();
+-    guint cursor_pos = m_lookup_table.cursorPos ();
+-
+-    if (G_UNLIKELY (i >= page_size))
+-        return FALSE;
+-    i += (cursor_pos / page_size) * page_size;
+-
+-    return selectCandidate (i);
+-}
+-
+-};
+diff --git a/src/PYLibPinyinBaseEditor.h b/src/PYLibPinyinBaseEditor.h
+deleted file mode 100644
+index fa5755c..0000000
+--- a/src/PYLibPinyinBaseEditor.h
++++ /dev/null
+@@ -1,90 +0,0 @@
+-/* vim:set et ts=4 sts=4:
+- *
+- * ibus-pinyin - The Chinese PinYin engine for IBus
+- *
+- * Copyright (c) 2011 Peng Wu <alexepico at gmail.com>
+- *
+- * 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.
+- */
+-#ifndef __PY_LIB_PINYIN_BASE_EDITOR_H_
+-#define __PY_LIB_PINYIN_BASE_EDITOR_H_
+-
+-#include "PYLookupTable.h"
+-#include "PYEditor.h"
+-#include "PYPinyinParser.h"
+-#include "PYSpecialPhraseTable.h"
+-
+-namespace PY {
+-
+-class LibPinyinBaseEditor : public Editor {
+-public:
+-    LibPinyinBaseEditor (PinyinProperties & props, Config & config);
+-
+-public:
+-    /* virtual functions */
+-    virtual void pageUp (void);
+-    virtual void pageDown (void);
+-    virtual void cursorUp (void);
+-    virtual void cursorDown (void);
+-    virtual void update (void);
+-    virtual void reset (void);
+-    virtual void candidateClicked (guint index, guint button, guint state);
+-    virtual gboolean processKeyEvent (guint keyval, guint keycode, guint modifiers);
+-    virtual gboolean processSpace (guint keyval, guint keycode, guint modifiers);
+-    virtual gboolean processFunctionKey (guint keyval, guint keycode, guint modifiers);
+-    virtual void updateLookupTable ();
+-    virtual void updateLookupTableFast ();
+-    virtual gboolean fillLookupTableByPage ();
+-
+-protected:
+-
+-    gboolean updateSpecialPhrases ();
+-    gboolean selectCandidate (guint i);
+-    gboolean selectCandidateInPage (guint i);
+-
+-    void commit (const gchar *str);
+-
+-    /* inline functions */
+-
+-    /* pure virtual functions */
+-    virtual gboolean insert (gint ch) = 0;
+-    virtual gboolean removeCharBefore (void) = 0;
+-    virtual gboolean removeCharAfter (void) = 0;
+-    virtual gboolean removeWordBefore (void) = 0;
+-    virtual gboolean removeWordAfter (void) = 0;
+-    virtual gboolean moveCursorLeft (void) = 0;
+-    virtual gboolean moveCursorRight (void) = 0;
+-    virtual gboolean moveCursorLeftByWord (void) = 0;
+-    virtual gboolean moveCursorRightByWord (void) = 0;
+-    virtual gboolean moveCursorToBegin (void) = 0;
+-    virtual gboolean moveCursorToEnd (void) = 0;
+-    virtual void commit (void) = 0;
+-    virtual void updateAuxiliaryText (void) = 0;
+-    virtual void updatePreeditText (void) = 0;
+-
+-    /* varibles */
+-    PinyinArray                 m_pinyin;
+-    guint                       m_pinyin_len;
+-    LookupTable                 m_lookup_table;
+-    String                      m_buffer;
+-
+-    /* use LibPinyinBackEnd here. */
+-    std::vector<std::string>    m_special_phrases;
+-    std::string                 m_selected_special_phrase;
+-};
+-
+-};
+-
+-#endif
+diff --git a/src/PYLibPinyinDoublePinyinEditor.h b/src/PYLibPinyinDoublePinyinEditor.h
+deleted file mode 100644
+index 5ed106f..0000000
+--- a/src/PYLibPinyinDoublePinyinEditor.h
++++ /dev/null
+@@ -1,57 +0,0 @@
+-/* vim:set et ts=4 sts=4:
+- *
+- * ibus-pinyin - The Chinese PinYin engine for IBus
+- *
+- * Copyright (c) 2011 Peng Wu <alexepico at gmail.com>
+- *
+- * 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.
+- */
+-#ifndef __PY_LIB_PINYIN_DOUBLE_PINYIN_EDITOR_H_
+-#define __PY_LIB_PINYIN_DOUBLE_PINYIN_EDITOR_H_
+-
+-#include "PYLibPinyinBaseEditor.h"
+-
+-namespace PY {
+-
+-class LibPinyinDoublePinyinEditor : public LibPinyinBaseEditor {
+-
+-public:
+-    LibPinyinDoublePinyinEditor (PinyinProperties & props, Config & config);
+-
+-    gboolean insert (gint ch);
+-
+-    gboolean removeCharBefore (void);
+-    gboolean removeCharAfter (void);
+-    gboolean removeWordBefore (void);
+-    gboolean removeWordAfter (void);
+-
+-    gboolean moveCursorLeft (void);
+-    gboolean moveCursorRight (void);
+-    gboolean moveCursorLeftByWord (void);
+-    gboolean moveCursorRightByWord (void);
+-    gboolean moveCursorToBegin (void);
+-    gboolean moveCursorToEnd (void);
+-
+-    /* override virtual functions */
+-    gboolean processKeyEvent (guint keyval, guint keycode, guint modifiers);
+-    void reset (void);
+-
+-protected:
+-    /* TODO: to be implemented. */
+-};
+-
+-};
+-
+-#endif
+diff --git a/src/PYLibPinyinFullPinyinEditor.h b/src/PYLibPinyinFullPinyinEditor.h
+deleted file mode 100644
+index dcc1728..0000000
+--- a/src/PYLibPinyinFullPinyinEditor.h
++++ /dev/null
+@@ -1,59 +0,0 @@
+-/* vim:set et ts=4 sts=4:
+- *
+- * ibus-pinyin - The Chinese PinYin engine for IBus
+- *
+- * Copyright (c) 2011 Peng Wu <alexepico at gmail.com>
+- *
+- * 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.
+- */
+-#ifndef __PY_LIB_PINYIN_FULL_PINYIN_EDITOR_H
+-#define __PY_LIB_PINYIN_FULL_PINYIN_EDITOR_H
+-
+-#include "PYLibPinyinBaseEditor.h"
+-
+-namespace PY {
+-
+-class LibPinyinFullPinyinEditor : public PinyinEditor {
+-
+-public:
+-    LibPinyinFullPinyinEditor (PinyinProperties & props, Config & config);
+-    ~LibPinyinFullPinyinEditor (void);
+-
+-public:
+-    gboolean insert (gint ch);
+-
+-    gboolean removeCharBefore (void);
+-    gboolean removeCharAfter (void);
+-    gboolean removeWordBefore (void);
+-    gboolean removeWordAfter (void);
+-
+-    gboolean moveCursorLeft (void);
+-    gboolean moveCursorRight (void);
+-    gboolean moveCursorLeftByWord (void);
+-    gboolean moveCursorRightByWord (void);
+-    gboolean moveCursorToBegin (void);
+-    gboolean moveCursorToEnd (void);
+-
+-    /* virtual functions */
+-    virtual gboolean processKeyEvent (guint keyval, guint keycode, guint modifiers);
+-    virtual void reset (void);
+-
+-protected:
+-    /* TODO: to be implemented. */
+-};
+-
+-};
+-
+-#endif
+diff --git a/src/PYPDoublePinyinEditor.h b/src/PYPDoublePinyinEditor.h
+new file mode 100644
+index 0000000..5ed106f
+--- /dev/null
++++ b/src/PYPDoublePinyinEditor.h
+@@ -0,0 +1,57 @@
++/* vim:set et ts=4 sts=4:
++ *
++ * ibus-pinyin - The Chinese PinYin engine for IBus
++ *
++ * Copyright (c) 2011 Peng Wu <alexepico at gmail.com>
++ *
++ * 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.
++ */
++#ifndef __PY_LIB_PINYIN_DOUBLE_PINYIN_EDITOR_H_
++#define __PY_LIB_PINYIN_DOUBLE_PINYIN_EDITOR_H_
++
++#include "PYLibPinyinBaseEditor.h"
++
++namespace PY {
++
++class LibPinyinDoublePinyinEditor : public LibPinyinBaseEditor {
++
++public:
++    LibPinyinDoublePinyinEditor (PinyinProperties & props, Config & config);
++
++    gboolean insert (gint ch);
++
++    gboolean removeCharBefore (void);
++    gboolean removeCharAfter (void);
++    gboolean removeWordBefore (void);
++    gboolean removeWordAfter (void);
++
++    gboolean moveCursorLeft (void);
++    gboolean moveCursorRight (void);
++    gboolean moveCursorLeftByWord (void);
++    gboolean moveCursorRightByWord (void);
++    gboolean moveCursorToBegin (void);
++    gboolean moveCursorToEnd (void);
++
++    /* override virtual functions */
++    gboolean processKeyEvent (guint keyval, guint keycode, guint modifiers);
++    void reset (void);
++
++protected:
++    /* TODO: to be implemented. */
++};
++
++};
++
++#endif
+diff --git a/src/PYPFullPinyinEditor.h b/src/PYPFullPinyinEditor.h
+new file mode 100644
+index 0000000..dcc1728
+--- /dev/null
++++ b/src/PYPFullPinyinEditor.h
+@@ -0,0 +1,59 @@
++/* vim:set et ts=4 sts=4:
++ *
++ * ibus-pinyin - The Chinese PinYin engine for IBus
++ *
++ * Copyright (c) 2011 Peng Wu <alexepico at gmail.com>
++ *
++ * 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.
++ */
++#ifndef __PY_LIB_PINYIN_FULL_PINYIN_EDITOR_H
++#define __PY_LIB_PINYIN_FULL_PINYIN_EDITOR_H
++
++#include "PYLibPinyinBaseEditor.h"
++
++namespace PY {
++
++class LibPinyinFullPinyinEditor : public PinyinEditor {
++
++public:
++    LibPinyinFullPinyinEditor (PinyinProperties & props, Config & config);
++    ~LibPinyinFullPinyinEditor (void);
++
++public:
++    gboolean insert (gint ch);
++
++    gboolean removeCharBefore (void);
++    gboolean removeCharAfter (void);
++    gboolean removeWordBefore (void);
++    gboolean removeWordAfter (void);
++
++    gboolean moveCursorLeft (void);
++    gboolean moveCursorRight (void);
++    gboolean moveCursorLeftByWord (void);
++    gboolean moveCursorRightByWord (void);
++    gboolean moveCursorToBegin (void);
++    gboolean moveCursorToEnd (void);
++
++    /* virtual functions */
++    virtual gboolean processKeyEvent (guint keyval, guint keycode, guint modifiers);
++    virtual void reset (void);
++
++protected:
++    /* TODO: to be implemented. */
++};
++
++};
++
++#endif
+diff --git a/src/PYPPhoneticEditor.cc b/src/PYPPhoneticEditor.cc
+new file mode 100644
+index 0000000..6fdd5ef
+--- /dev/null
++++ b/src/PYPPhoneticEditor.cc
+@@ -0,0 +1,332 @@
++/* vim:set et ts=4 sts=4:
++ *
++ * ibus-pinyin - The Chinese PinYin engine for IBus
++ *
++ * Copyright (c) 2011 Peng Wu <alexepico at gmail.com>
++ *
++ * 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 "PYLibPinyinBaseEditor.h"
++#include "PYConfig.h"
++#include "PYPinyinProperties.h"
++#include "PYSimpTradConverter.h"
++
++namespace PY {
++/* init static members */
++LibPinyinBaseEditor::LibPinyinBaseEditor (PinyinProperties &props,
++                                          Config &config):
++    Editor (props, config),
++    m_pinyin (MAX_PHRASE_LEN),
++    m_pinyin_len (0),
++    m_lookup_table (m_config.pageSize ())
++{
++}
++
++gboolean
++LibPinyinBaseEditor::processSpace (guint keyval, guint keycode,
++                                   guint modifiers)
++{
++    if (!m_text)
++        return FALSE;
++    if (cmshm_filter (modifiers) != 0)
++        return TRUE;
++    if (m_lookup_table.size () != 0) {
++        selectCandidate (m_lookup_table.cursorPos ());
++    } else {
++        commit ();
++    }
++    return TRUE;
++}
++
++gboolean
++LibPinyinBaseEditor::processFunctionKey (guint keyval, guint keycode, guint modifiers)
++{
++    if (m_text.empty ())
++        return FALSE;
++
++    /* ignore numlock */
++    modifiers = cmshm_filter (modifiers);
++
++    if (modifiers != 0 && modifiers != IBUS_CONTROL_MASK)
++        return TRUE;
++
++    /* process some cursor control keys */
++    if (modifiers == 0) {  /* no modifiers. */
++        switch (keyval) {
++        case IBUS_Return:
++        case IBUS_KP_Enter:
++            commit ();
++            return TRUE;
++
++        case IBUS_BackSpace:
++            removeCharBefore ();
++            return TRUE;
++
++        case IBUS_Delete:
++        case IBUS_KP_Delete:
++            removeCharAfter ();
++            return TRUE;
++
++        case IBUS_Left:
++        case IBUS_KP_Left:
++            moveCursorLeft ();
++            return TRUE;
++
++        case IBUS_Right:
++        case IBUS_KP_Right:
++            moveCursorRight ();
++            return TRUE;
++
++        case IBUS_Home:
++        case IBUS_KP_Home:
++            moveCursorToBegin ();
++            return TRUE;
++
++        case IBUS_End:
++        case IBUS_KP_End:
++            moveCursorToEnd ();
++            return TRUE;
++
++        case IBUS_Up:
++        case IBUS_KP_Up:
++            cursorUp ();
++            return TRUE;
++
++        case IBUS_Down:
++        case IBUS_KP_Down:
++            cursorDown ();
++            return TRUE;
++
++        case IBUS_Page_Up:
++        case IBUS_KP_Page_Up:
++            pageUp ();
++            return TRUE;
++
++        case IBUS_Page_Down:
++        case IBUS_KP_Page_Down:
++        case IBUS_Tab:
++            pageDown ();
++            return TRUE;
++
++        case IBUS_Escape:
++            reset ();
++            return TRUE;
++        default:
++            return TRUE;
++        }
++    } else { /* ctrl key pressed. */
++        switch (keyval) {
++        case IBUS_BackSpace:
++            removeWordBefore ();
++            return TRUE;
++
++        case IBUS_Delete:
++        case IBUS_KP_Delete:
++            removeWordAfter ();
++            return TRUE;
++
++        case IBUS_Left:
++        case IBUS_KP_Left:
++            moveCursorLeftByWord ();
++            return TRUE;
++
++        case IBUS_Right:
++        case IBUS_KP_Right:
++            moveCursorToEnd ();
++            return TRUE;
++
++        default:
++            return TRUE;
++        }
++    }
++    return TRUE;
++}
++
++gboolean
++LibPinyinBaseEditor::processKeyEvent (guint keyval, guint keycode, guint modifiers)
++{
++    return FALSE;
++}
++
++gboolean
++LibPinyinBaseEditor::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;
++
++    /* Note: change behavior to match the entire m_text,
++     *         instead of partial m_text.
++     */
++    SpecialPhraseTable::instance ().lookup
++        (m_text, m_special_phrases);
++
++    return size != m_special_phrases.size() || size != 0;
++}
++
++void
++LibPinyinBaseEditor::updateLookupTableFast (void)
++{
++    Editor::updateLookupTableFast (m_lookup_table, TRUE);
++}
++
++void
++LibPinyinBaseEditor::updateLookupTable (void)
++{
++    m_lookup_table.clear ();
++
++    fillLookupTableByPage ();
++    if (m_lookup_table.size()) {
++        Editor::updateLookupTable (m_lookup_table, TRUE);
++    } else {
++        hideLookupTable ();
++    }
++}
++
++gboolean
++LibPinyinBaseEditor::fillLookupTableByPage (void)
++{
++    if (!m_selected_special_phrase.empty ()) {
++        return FALSE;
++    }
++
++    guint filled_nr = m_lookup_table.size ();
++    guint page_size = m_lookup_table.pageSize ();
++
++    /* fill lookup table by libpinyin get candidates. */
++    g_assert(FALSE);
++}
++
++void
++LibPinyinBaseEditor::pageUp (void)
++{
++    if (G_LIKELY (m_lookup_table.pageUp ())) {
++        updateLookupTableFast ();
++        updatePreeditText ();
++        updateAuxiliaryText ();
++    }
++}
++
++void
++LibPinyinBaseEditor::pageDown (void)
++{
++    if (G_LIKELY((m_lookup_table.pageDown ()) ||
++                 (fillLookupTableByPage () && m_lookup_table.pageDown()))) {
++        updateLookupTableFast ();
++        updatePreeditText ();
++        updateAuxiliaryText ();
++    }
++}
++
++void
++LibPinyinBaseEditor::cursorUp (void)
++{
++    if (G_LIKELY (m_lookup_table.cursorUp ())) {
++        updateLookupTableFast ();
++        updatePreeditText ();
++        updateAuxiliaryText ();
++    }
++}
++
++void
++LibPinyinBaseEditor::cursorDown (void)
++{
++    if (G_LIKELY ((m_lookup_table.cursorPos () == m_lookup_table.size() - 1) &&
++                  (fillLookupTableByPage () == FALSE))) {
++        return;
++    }
++
++    if (G_LIKELY (m_lookup_table.cursorDown ())) {
++        updateLookupTableFast ();
++        updatePreeditText ();
++        updateAuxiliaryText ();
++    }
++}
++
++void
++LibPinyinBaseEditor::candidateClicked (guint index, guint button, guint state)
++{
++    selectCandidateInPage (index);
++}
++
++void
++LibPinyinBaseEditor::reset (void)
++{
++    m_pinyin.clear ();
++    m_pinyin_len = 0;
++    m_lookup_table.clear ();
++    m_special_phrases.clear ();
++    m_selected_special_phrase.clear ();
++
++    Editor::reset ();
++}
++
++void
++LibPinyinBaseEditor::update (void)
++{
++    updateLookupTable ();
++    updatePreeditText ();
++    updateAuxiliaryText ();
++}
++
++void
++LibPinyinBaseEditor::commit (const gchar *str)
++{
++    StaticText text(str);
++    commitText (text);
++}
++
++gboolean
++LibPinyinBaseEditor::selectCandidate (guint i)
++{
++
++    if (i < m_special_phrases.size ()) {
++        /* select a special phrase */
++        m_selected_special_phrase = m_special_phrases[i];
++        if (m_cursor == m_text.size()) {
++            m_buffer = m_selected_special_phrase;
++            reset ();
++            commit ((const gchar *)m_buffer);
++        } else {
++            updateSpecialPhrases ();
++            update ();
++        }
++        return TRUE;
++    }
++
++    i -= m_special_phrases.size ();
++    /* TODO: deal with normal candidates selection here by libpinyin. */
++    g_assert (FALSE);
++}
++
++gboolean
++LibPinyinBaseEditor::selectCandidateInPage (guint i)
++{
++    guint page_size = m_lookup_table.pageSize ();
++    guint cursor_pos = m_lookup_table.cursorPos ();
++
++    if (G_UNLIKELY (i >= page_size))
++        return FALSE;
++    i += (cursor_pos / page_size) * page_size;
++
++    return selectCandidate (i);
++}
++
++};
+diff --git a/src/PYPPhoneticEditor.h b/src/PYPPhoneticEditor.h
+new file mode 100644
+index 0000000..fa5755c
+--- /dev/null
++++ b/src/PYPPhoneticEditor.h
+@@ -0,0 +1,90 @@
++/* vim:set et ts=4 sts=4:
++ *
++ * ibus-pinyin - The Chinese PinYin engine for IBus
++ *
++ * Copyright (c) 2011 Peng Wu <alexepico at gmail.com>
++ *
++ * 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.
++ */
++#ifndef __PY_LIB_PINYIN_BASE_EDITOR_H_
++#define __PY_LIB_PINYIN_BASE_EDITOR_H_
++
++#include "PYLookupTable.h"
++#include "PYEditor.h"
++#include "PYPinyinParser.h"
++#include "PYSpecialPhraseTable.h"
++
++namespace PY {
++
++class LibPinyinBaseEditor : public Editor {
++public:
++    LibPinyinBaseEditor (PinyinProperties & props, Config & config);
++
++public:
++    /* virtual functions */
++    virtual void pageUp (void);
++    virtual void pageDown (void);
++    virtual void cursorUp (void);
++    virtual void cursorDown (void);
++    virtual void update (void);
++    virtual void reset (void);
++    virtual void candidateClicked (guint index, guint button, guint state);
++    virtual gboolean processKeyEvent (guint keyval, guint keycode, guint modifiers);
++    virtual gboolean processSpace (guint keyval, guint keycode, guint modifiers);
++    virtual gboolean processFunctionKey (guint keyval, guint keycode, guint modifiers);
++    virtual void updateLookupTable ();
++    virtual void updateLookupTableFast ();
++    virtual gboolean fillLookupTableByPage ();
++
++protected:
++
++    gboolean updateSpecialPhrases ();
++    gboolean selectCandidate (guint i);
++    gboolean selectCandidateInPage (guint i);
++
++    void commit (const gchar *str);
++
++    /* inline functions */
++
++    /* pure virtual functions */
++    virtual gboolean insert (gint ch) = 0;
++    virtual gboolean removeCharBefore (void) = 0;
++    virtual gboolean removeCharAfter (void) = 0;
++    virtual gboolean removeWordBefore (void) = 0;
++    virtual gboolean removeWordAfter (void) = 0;
++    virtual gboolean moveCursorLeft (void) = 0;
++    virtual gboolean moveCursorRight (void) = 0;
++    virtual gboolean moveCursorLeftByWord (void) = 0;
++    virtual gboolean moveCursorRightByWord (void) = 0;
++    virtual gboolean moveCursorToBegin (void) = 0;
++    virtual gboolean moveCursorToEnd (void) = 0;
++    virtual void commit (void) = 0;
++    virtual void updateAuxiliaryText (void) = 0;
++    virtual void updatePreeditText (void) = 0;
++
++    /* varibles */
++    PinyinArray                 m_pinyin;
++    guint                       m_pinyin_len;
++    LookupTable                 m_lookup_table;
++    String                      m_buffer;
++
++    /* use LibPinyinBackEnd here. */
++    std::vector<std::string>    m_special_phrases;
++    std::string                 m_selected_special_phrase;
++};
++
++};
++
++#endif
+-- 
+1.7.6.4
+
+
+From b8f7e09a3316035b2b497386885a41e52da7b664 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Fri, 2 Sep 2011 15:39:31 +0800
+Subject: [PATCH 10/71] add libpinyin pinyin editor header
+
+---
+ src/PYPPinyinEditor.h |   56 +++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 files changed, 56 insertions(+), 0 deletions(-)
+ create mode 100644 src/PYPPinyinEditor.h
+
+diff --git a/src/PYPPinyinEditor.h b/src/PYPPinyinEditor.h
+new file mode 100644
+index 0000000..4213395
+--- /dev/null
++++ b/src/PYPPinyinEditor.h
+@@ -0,0 +1,56 @@
++/* vim:set et ts=4 sts=4:
++ *
++ * ibus-pinyin - The Chinese PinYin engine for IBus
++ *
++ * Copyright (c) 2011 Peng Wu <alexepico at gmail.com>
++ *
++ * 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.
++ */
++#ifndef __PY_LIB_PINYIN_PINYIN_EDITOR_H_
++#define __PY_LIB_PINYIN_PINYIN_EDITOR_H_
++
++#include "PYPPhoneticEditor.h"
++
++namespace PY {
++
++class Config;
++
++#define MAX_PINYIN_LEN 64
++
++class SpecialPhraseTable;
++
++class LibPinyinPinyinEditor : public LibPinyinPhoneticEditor {
++public:
++    LibPinyinPinyinEditor (PinyinProperties & props, Config & config);
++
++protected:
++    gboolean processPinyin (guint keyval, guint keycode, guint modifiers);
++    gboolean processNumber (guint keyval, guint keycode, guint modifiers);
++    gboolean processPunct (guint keyval, guint keycode, guint modifiers);
++    gboolean processFunctionKey (guint keyval, guint keycode, guint modifiers);
++
++    void commit ();
++
++    void updateAuxiliaryText (void);
++    void updateLookupTable (void);
++    void updatePreeditText (void);
++
++    virtual gboolean processKeyEvent (guint keyval, guint keycode, guint modifiers);
++
++};
++
++};
++
++#endif
+-- 
+1.7.6.4
+
+
+From 0d7fdc1f9b71df881fa4353fc0f20a0839c0c78c Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Fri, 2 Sep 2011 15:49:13 +0800
+Subject: [PATCH 11/71] rename base editor
+
+---
+ src/Makefile.am             |    6 +++-
+ src/PYPDoublePinyinEditor.h |    4 +-
+ src/PYPFullPinyinEditor.h   |    4 +-
+ src/PYPPhoneticEditor.cc    |   47 ++++++++++++++++++++++---------------------
+ src/PYPPhoneticEditor.h     |    4 +-
+ src/PYPPinyinEditor.cc      |   22 ++++++++++++++++++++
+ src/PYPPinyinEditor.h       |    4 +-
+ 7 files changed, 58 insertions(+), 33 deletions(-)
+ create mode 100644 src/PYPPinyinEditor.cc
+
+diff --git a/src/Makefile.am b/src/Makefile.am
+index a104c75..ddebb04 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -64,7 +64,8 @@ ibus_engine_pinyin_c_sources = \
+ 	PYDynamicSpecialPhrase.cc \
+ 	PYSpecialPhrase.cc \
+ 	PYSpecialPhraseTable.cc \
+-	PYLibPinyinBaseEditor.cc \
++	PYPPhoneticEditor.cc \
++	PYPPinyinEditor.cc \
+ 	$(NULL)
+ ibus_engine_pinyin_h_sources = \
+ 	PYBopomofo.h \
+@@ -108,7 +109,8 @@ ibus_engine_pinyin_h_sources = \
+ 	PYUtil.h \
+ 	PYEnglishEditor.h \
+ 	PYLibPinyin.h \
+-	PYLibPinyinBaseEditor.h \
++	PYPPhoneticEditor.h \
++	PYPPinyinEditor.h \
+ 	$(NULL)
+ 
+ if IBUS_BUILD_LUA_EXTENSION
+diff --git a/src/PYPDoublePinyinEditor.h b/src/PYPDoublePinyinEditor.h
+index 5ed106f..35baa6f 100644
+--- a/src/PYPDoublePinyinEditor.h
++++ b/src/PYPDoublePinyinEditor.h
+@@ -21,11 +21,11 @@
+ #ifndef __PY_LIB_PINYIN_DOUBLE_PINYIN_EDITOR_H_
+ #define __PY_LIB_PINYIN_DOUBLE_PINYIN_EDITOR_H_
+ 
+-#include "PYLibPinyinBaseEditor.h"
++#include "PYPPinyinEditor.h"
+ 
+ namespace PY {
+ 
+-class LibPinyinDoublePinyinEditor : public LibPinyinBaseEditor {
++class LibPinyinDoublePinyinEditor : public LibPinyinPinyinEditor {
+ 
+ public:
+     LibPinyinDoublePinyinEditor (PinyinProperties & props, Config & config);
+diff --git a/src/PYPFullPinyinEditor.h b/src/PYPFullPinyinEditor.h
+index dcc1728..a6e74c4 100644
+--- a/src/PYPFullPinyinEditor.h
++++ b/src/PYPFullPinyinEditor.h
+@@ -21,11 +21,11 @@
+ #ifndef __PY_LIB_PINYIN_FULL_PINYIN_EDITOR_H
+ #define __PY_LIB_PINYIN_FULL_PINYIN_EDITOR_H
+ 
+-#include "PYLibPinyinBaseEditor.h"
++#include "PYPPinyinEditor.h"
+ 
+ namespace PY {
+ 
+-class LibPinyinFullPinyinEditor : public PinyinEditor {
++class LibPinyinFullPinyinEditor : public LibPinyinPinyinEditor {
+ 
+ public:
+     LibPinyinFullPinyinEditor (PinyinProperties & props, Config & config);
+diff --git a/src/PYPPhoneticEditor.cc b/src/PYPPhoneticEditor.cc
+index 6fdd5ef..ef9a02d 100644
+--- a/src/PYPPhoneticEditor.cc
++++ b/src/PYPPhoneticEditor.cc
+@@ -18,15 +18,16 @@
+  * along with this program; if not, write to the Free Software
+  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+  */
+-#include "PYLibPinyinBaseEditor.h"
++#include "PYPPhoneticEditor.h"
+ #include "PYConfig.h"
+ #include "PYPinyinProperties.h"
+ #include "PYSimpTradConverter.h"
+ 
+-namespace PY {
++using namespace PY;
++
+ /* init static members */
+-LibPinyinBaseEditor::LibPinyinBaseEditor (PinyinProperties &props,
+-                                          Config &config):
++LibPinyinPhoneticEditor::LibPinyinPhoneticEditor (PinyinProperties &props,
++                                                  Config &config):
+     Editor (props, config),
+     m_pinyin (MAX_PHRASE_LEN),
+     m_pinyin_len (0),
+@@ -35,8 +36,8 @@ LibPinyinBaseEditor::LibPinyinBaseEditor (PinyinProperties &props,
+ }
+ 
+ gboolean
+-LibPinyinBaseEditor::processSpace (guint keyval, guint keycode,
+-                                   guint modifiers)
++LibPinyinPhoneticEditor::processSpace (guint keyval, guint keycode,
++                                       guint modifiers)
+ {
+     if (!m_text)
+         return FALSE;
+@@ -51,7 +52,7 @@ LibPinyinBaseEditor::processSpace (guint keyval, guint keycode,
+ }
+ 
+ gboolean
+-LibPinyinBaseEditor::processFunctionKey (guint keyval, guint keycode, guint modifiers)
++LibPinyinPhoneticEditor::processFunctionKey (guint keyval, guint keycode, guint modifiers)
+ {
+     if (m_text.empty ())
+         return FALSE;
+@@ -155,13 +156,13 @@ LibPinyinBaseEditor::processFunctionKey (guint keyval, guint keycode, guint modi
+ }
+ 
+ gboolean
+-LibPinyinBaseEditor::processKeyEvent (guint keyval, guint keycode, guint modifiers)
++LibPinyinPhoneticEditor::processKeyEvent (guint keyval, guint keycode, guint modifiers)
+ {
+     return FALSE;
+ }
+ 
+ gboolean
+-LibPinyinBaseEditor::updateSpecialPhrases (void)
++LibPinyinPhoneticEditor::updateSpecialPhrases (void)
+ {
+     guint size = m_special_phrases.size();
+     m_special_phrases.clear ();
+@@ -182,13 +183,13 @@ LibPinyinBaseEditor::updateSpecialPhrases (void)
+ }
+ 
+ void
+-LibPinyinBaseEditor::updateLookupTableFast (void)
++LibPinyinPhoneticEditor::updateLookupTableFast (void)
+ {
+     Editor::updateLookupTableFast (m_lookup_table, TRUE);
+ }
+ 
+ void
+-LibPinyinBaseEditor::updateLookupTable (void)
++LibPinyinPhoneticEditor::updateLookupTable (void)
+ {
+     m_lookup_table.clear ();
+ 
+@@ -201,7 +202,7 @@ LibPinyinBaseEditor::updateLookupTable (void)
+ }
+ 
+ gboolean
+-LibPinyinBaseEditor::fillLookupTableByPage (void)
++LibPinyinPhoneticEditor::fillLookupTableByPage (void)
+ {
+     if (!m_selected_special_phrase.empty ()) {
+         return FALSE;
+@@ -215,7 +216,7 @@ LibPinyinBaseEditor::fillLookupTableByPage (void)
+ }
+ 
+ void
+-LibPinyinBaseEditor::pageUp (void)
++LibPinyinPhoneticEditor::pageUp (void)
+ {
+     if (G_LIKELY (m_lookup_table.pageUp ())) {
+         updateLookupTableFast ();
+@@ -225,7 +226,7 @@ LibPinyinBaseEditor::pageUp (void)
+ }
+ 
+ void
+-LibPinyinBaseEditor::pageDown (void)
++LibPinyinPhoneticEditor::pageDown (void)
+ {
+     if (G_LIKELY((m_lookup_table.pageDown ()) ||
+                  (fillLookupTableByPage () && m_lookup_table.pageDown()))) {
+@@ -236,7 +237,7 @@ LibPinyinBaseEditor::pageDown (void)
+ }
+ 
+ void
+-LibPinyinBaseEditor::cursorUp (void)
++LibPinyinPhoneticEditor::cursorUp (void)
+ {
+     if (G_LIKELY (m_lookup_table.cursorUp ())) {
+         updateLookupTableFast ();
+@@ -246,7 +247,7 @@ LibPinyinBaseEditor::cursorUp (void)
+ }
+ 
+ void
+-LibPinyinBaseEditor::cursorDown (void)
++LibPinyinPhoneticEditor::cursorDown (void)
+ {
+     if (G_LIKELY ((m_lookup_table.cursorPos () == m_lookup_table.size() - 1) &&
+                   (fillLookupTableByPage () == FALSE))) {
+@@ -261,13 +262,13 @@ LibPinyinBaseEditor::cursorDown (void)
+ }
+ 
+ void
+-LibPinyinBaseEditor::candidateClicked (guint index, guint button, guint state)
++LibPinyinPhoneticEditor::candidateClicked (guint index, guint button, guint state)
+ {
+     selectCandidateInPage (index);
+ }
+ 
+ void
+-LibPinyinBaseEditor::reset (void)
++LibPinyinPhoneticEditor::reset (void)
+ {
+     m_pinyin.clear ();
+     m_pinyin_len = 0;
+@@ -279,7 +280,7 @@ LibPinyinBaseEditor::reset (void)
+ }
+ 
+ void
+-LibPinyinBaseEditor::update (void)
++LibPinyinPhoneticEditor::update (void)
+ {
+     updateLookupTable ();
+     updatePreeditText ();
+@@ -287,14 +288,14 @@ LibPinyinBaseEditor::update (void)
+ }
+ 
+ void
+-LibPinyinBaseEditor::commit (const gchar *str)
++LibPinyinPhoneticEditor::commit (const gchar *str)
+ {
+     StaticText text(str);
+     commitText (text);
+ }
+ 
+ gboolean
+-LibPinyinBaseEditor::selectCandidate (guint i)
++LibPinyinPhoneticEditor::selectCandidate (guint i)
+ {
+ 
+     if (i < m_special_phrases.size ()) {
+@@ -317,7 +318,7 @@ LibPinyinBaseEditor::selectCandidate (guint i)
+ }
+ 
+ gboolean
+-LibPinyinBaseEditor::selectCandidateInPage (guint i)
++LibPinyinPhoneticEditor::selectCandidateInPage (guint i)
+ {
+     guint page_size = m_lookup_table.pageSize ();
+     guint cursor_pos = m_lookup_table.cursorPos ();
+@@ -329,4 +330,4 @@ LibPinyinBaseEditor::selectCandidateInPage (guint i)
+     return selectCandidate (i);
+ }
+ 
+-};
++
+diff --git a/src/PYPPhoneticEditor.h b/src/PYPPhoneticEditor.h
+index fa5755c..3d64bc4 100644
+--- a/src/PYPPhoneticEditor.h
++++ b/src/PYPPhoneticEditor.h
+@@ -28,9 +28,9 @@
+ 
+ namespace PY {
+ 
+-class LibPinyinBaseEditor : public Editor {
++class LibPinyinPhoneticEditor : public Editor {
+ public:
+-    LibPinyinBaseEditor (PinyinProperties & props, Config & config);
++    LibPinyinPhoneticEditor (PinyinProperties & props, Config & config);
+ 
+ public:
+     /* virtual functions */
+diff --git a/src/PYPPinyinEditor.cc b/src/PYPPinyinEditor.cc
+new file mode 100644
+index 0000000..a259a99
+--- /dev/null
++++ b/src/PYPPinyinEditor.cc
+@@ -0,0 +1,22 @@
++/* vim:set et ts=4 sts=4:
++ *
++ * ibus-pinyin - The Chinese PinYin engine for IBus
++ *
++ * Copyright (c) 2011 Peng Wu <alexepico at gmail.com>
++ *
++ * 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 "PYPPinyinEditor.h"
+diff --git a/src/PYPPinyinEditor.h b/src/PYPPinyinEditor.h
+index 4213395..fd2b2ce 100644
+--- a/src/PYPPinyinEditor.h
++++ b/src/PYPPinyinEditor.h
+@@ -25,10 +25,10 @@
+ 
+ namespace PY {
+ 
+-class Config;
+-
+ #define MAX_PINYIN_LEN 64
+ 
++class Config;
++
+ class SpecialPhraseTable;
+ 
+ class LibPinyinPinyinEditor : public LibPinyinPhoneticEditor {
+-- 
+1.7.6.4
+
+
+From 21c05a2bf76d58a2928fd6e93c2e1f561129ee8f Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Fri, 2 Sep 2011 16:49:00 +0800
+Subject: [PATCH 12/71] begin to write pinyin editor
+
+---
+ src/PYPPinyinEditor.cc |  202 ++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 files changed, 202 insertions(+), 0 deletions(-)
+
+diff --git a/src/PYPPinyinEditor.cc b/src/PYPPinyinEditor.cc
+index a259a99..a78544d 100644
+--- a/src/PYPPinyinEditor.cc
++++ b/src/PYPPinyinEditor.cc
+@@ -20,3 +20,205 @@
+  */
+ 
+ #include "PYPPinyinEditor.h"
++#include "PYConfig.h"
++#include "PYPinyinProperties.h"
++#include "PYSimpTradConverter.h"
++#include "PYHalfFullConverter.h"
++
++using namespace PY;
++
++/* init static members*/
++LibPinyinPinyinEditor::LibPinyinPinyinEditor (PinyinProperties & props,
++                                              Config & config)
++    : LibPinyinPhoneticEditor (props, config)
++{
++}
++
++
++/**
++ * process pinyin
++ */
++inline gboolean
++LibPinyinPinyinEditor::processPinyin (guint keyval, guint keycode,
++                                      guint modifiers)
++{
++    if (G_UNLIKELY (cmshm_filter (modifiers) != 0))
++        return m_text ? TRUE : FALSE;
++
++    return insert (keyval);
++}
++
++/**
++ * process numbers
++ */
++inline gboolean
++LibPinyinPinyinEditor::processNumber (guint keyval, guint keycode,
++                                      guint modifiers)
++{
++    guint i;
++
++    if (!m_text)
++        return FALSE;
++
++    switch (keyval) {
++    case IBUS_0:
++    case IBUS_KP_0:
++        i = 9;
++        break;
++    case IBUS_1 ... IBUS_9:
++        i = keyval - IBUS_1;
++        break;
++    case IBUS_KP_1 ... IBUS_KP_9:
++        i = keyval - IBUS_KP_1;
++        break;
++    default:
++        g_return_val_if_reached (FALSE);
++    }
++
++    if (modifiers == 0)
++        selectCandidateInPage (i);
++
++    return TRUE;
++}
++
++inline gboolean
++LibPinyinPinyinEditor::processPunct (guint keyval, guint keycode,
++                                     guint modifiers)
++{
++    if (m_text.empty ())
++        return FALSE;
++
++    if (cmshm_filter (modifiers) != 0)
++        return TRUE;
++
++    switch (keyval) {
++    case IBUS_apostrophe:
++        return insert (keyval);
++    case IBUS_comma:
++        if (m_config.commaPeriodPage ()) {
++            pageUp ();
++            return TRUE;
++        }
++        break;
++    case IBUS_minus:
++        if (m_config.minusEqualPage ()) {
++            pageUp ();
++            return TRUE;
++        }
++        break;
++    case IBUS_period:
++        if (m_config.commaPeriodPage ()) {
++            pageDown ();
++            return TRUE;
++        }
++        break;
++    case IBUS_equal:
++        if (m_config.minusEqualPage ()) {
++            pageDown ();
++            return TRUE;
++        }
++        break;
++    }
++
++    if (m_config.autoCommit ()) {
++        if (m_lookup_table.size ()) {
++            /* TODO: check here. */
++            selectCandidate (m_lookup_table.cursorPos ());
++        }
++        commit ();
++        return FALSE;
++    }
++
++    return TRUE;
++}
++
++inline gboolean
++LibPinyinPinyinEditor::processFunctionKey (guint keyval, guint keycode,
++                                           guint modifiers)
++{
++    if (m_text.empty ())
++        return FALSE;
++
++    /* ignore numlock */
++    modifiers = cmshm_filter (modifiers);
++
++    if (modifiers != 0 && modifiers != IBUS_CONTROL_MASK)
++        return TRUE;
++
++    /* process some cursor control keys */
++    if (modifiers == 0) { /* no modifiers. */
++        switch (keyval) {
++        case IBUS_Shift_L:
++            if (!m_config.shiftSelectCandidate ())
++                return FALSE;
++            selectCandidateInPage (1);
++            return TRUE;
++
++        case IBUS_Shift_R:
++            if (!m_config.shiftSelectCandidate ())
++                return FALSE;
++            selectCandidateInPage (2);
++            return TRUE;
++        }
++    }
++
++    return LibPinyinPhoneticEditor::processFunctionKey (keyval, keycode,
++                                                        modifiers);
++}
++
++gboolean
++LibPinyinPinyinEditor::processKeyEvent (guint keyval, guint keycode,
++                                        guint modifiers)
++{
++    modifiers &= (IBUS_SHIFT_MASK |
++                  IBUS_CONTROL_MASK |
++                  IBUS_MOD1_MASK |
++                  IBUS_SUPER_MASK |
++                  IBUS_HYPER_MASK |
++                  IBUS_META_MASK |
++                  IBUS_LOCK_MASK);
++
++    switch (keyval) {
++    /* letters */
++    case IBUS_a ... IBUS_z:
++        return processPinyin (keyval, keycode, modifiers);
++    case IBUS_0 ... IBUS_9:
++    case IBUS_KP_0 ... IBUS_KP_9:
++        return processNumber (keyval, keycode, modifiers);
++    case IBUS_exclam ... IBUS_slash:
++    case IBUS_colon ... IBUS_at:
++    case IBUS_bracketleft ... IBUS_quoteleft:
++    case IBUS_braceleft ... IBUS_asciitilde:
++        return processPunct (keyval, keycode, modifiers);
++    case IBUS_space:
++        return processSpace (keyval, keycode, modifiers);
++    default:
++        return processFunctionKey (keyval, keycode, modifiers);
++    }
++}
++
++void
++LibPinyinPinyinEditor::commit ()
++{
++    g_assert (FALSE);
++}
++
++void
++LibPinyinPinyinEditor::updatePreeditText ()
++{
++    g_assert (FALSE);
++}
++
++void
++LibPinyinPinyinEditor::updateAuxiliaryText ()
++{
++    g_assert (FALSE);
++}
++
++void
++LibPinyinPinyinEditor::updateLookupTable ()
++{
++    m_lookup_table.setPageSize (m_config.pageSize ());
++    m_lookup_table.setOrientation (m_config.orientation ());
++    LibPinyinPhoneticEditor::updateLookupTable ();
++}
+-- 
+1.7.6.4
+
+
+From b79504595353a90d85b025ab6f3bb426787f26b3 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Mon, 5 Sep 2011 16:59:49 +0800
+Subject: [PATCH 13/71] begin to write bopomofo editor
+
+---
+ src/PYPBopomofoEditor.cc |  374 ++++++++++++++++++++++++++++++++++++++++++++++
+ src/PYPBopomofoEditor.h  |   77 ++++++++++
+ 2 files changed, 451 insertions(+), 0 deletions(-)
+ create mode 100644 src/PYPBopomofoEditor.cc
+ create mode 100644 src/PYPBopomofoEditor.h
+
+diff --git a/src/PYPBopomofoEditor.cc b/src/PYPBopomofoEditor.cc
+new file mode 100644
+index 0000000..75c8ddc
+--- /dev/null
++++ b/src/PYPBopomofoEditor.cc
+@@ -0,0 +1,374 @@
++/* vim:set et ts=4 sts=4:
++ *
++ * ibus-pinyin - The Chinese PinYin engine for IBus
++ *
++ * Copyright (c) 2011 Peng Wu <alexepico at gmail.com>
++ *
++ * 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 "PYPBopomofoEditor.h"
++#include "PYConfig.h"
++#include "PYPinyinProperties.h"
++#include "PYSimpTradConverter.h"
++
++namespace PY {
++#include "PYBopomofoKeyboard.h"
++};
++
++using namespace PY;
++
++const static gchar * bopomofo_select_keys[] = {
++    "1234567890",
++    "asdfghjkl;",
++    "1qaz2wsxed",
++    "asdfzxcvgb",
++    "1234qweras",
++    "aoeu;qjkix",
++    "aoeuhtnsid",
++    "aoeuidhtns",
++    "qweasdzxcr"
++};
++
++LibPinyinBopomofoEditor::LibPinyinBopomofoEditor
++(PinyinProperties & props, Config & config)
++    : LibPinyinPhoneticEditor (props, config),
++      m_select_mode (FALSE)
++{
++}
++
++LibPinyinBopomofoEditor::~LibPinyinBopomofoEditor (void)
++{
++}
++
++void
++LibPinyinBopomofoEditor::reset (void)
++{
++    m_select_mode = FALSE;
++    LibPinyinPhoneticEditor::reset ();
++}
++
++gboolean
++LibPinyinBopomofoEditor::insert (gint ch)
++{
++    /* is full */
++    if (G_UNLIKELY (m_text.length () >= MAX_PINYIN_LEN))
++        return TRUE;
++
++    m_text.insert (m_cursor++, ch);
++    update ();
++
++    return TRUE;
++}
++
++gboolean
++LibPinyinBopomofoEditor::removeCharBefore (void)
++{
++    if (G_UNLIKELY (m_cursor == 0))
++        return FALSE;
++
++    m_cursor --;
++    m_text.erase (m_cursor, 1);
++    update();
++
++    return TRUE;
++}
++
++gboolean
++LibPinyinBopomofoEditor::removeCharAfter (void)
++{
++    if (G_UNLIKELY (m_cursor == m_text.length ()))
++        return FALSE;
++
++    m_text.erase (m_cursor, 1);
++    update ();
++
++    return TRUE;
++}
++
++gboolean
++LibPinyinBopomofoEditor::removeWordBefore (void)
++{
++    if (G_UNLIKELY (m_cursor == 0))
++        return FALSE;
++
++    guint cursor;
++    if (G_UNLIKELY (m_cursor > m_pinyin_len)) {
++        cursor = m_pinyin_len;
++    } else {
++        const Pinyin & p = *m_pinyin.back ();
++        cursor = m_cursor - p.len;
++        m_pinyin_len -= p.len;
++        m_pinyin.pop_back ();
++    }
++
++    m_text.erase (cursor, m_cursor - cursor);
++    m_cursor = cursor;
++    update();
++
++    return TRUE;
++}
++
++gboolean
++LibPinyinBopomofoEditor::removeWordAfter (void)
++{
++    if (G_UNLIKELY (m_cursor == m_text.length ()))
++        return FALSE;
++
++    /* TODO: remove one word instead of the sentence. */
++    m_text.erase (m_cursor, -1);
++    update ();
++    return TRUE;
++}
++
++gboolean
++LibPinyinBopomofoEditor::moveCursorLeft (void)
++{
++    if (G_UNLIKELY (m_cursor == 0))
++        return FALSE;
++
++    m_cursor --;
++    update ();
++
++    return TRUE;
++}
++
++gboolean
++LibPinyinBopomofoEditor::moveCursorRight (void)
++{
++    if (G_UNLIKELY (m_cursor == m_text.length ()))
++        return FALSE;
++
++    m_cursor ++;
++    update ();
++
++    return TRUE;
++}
++
++gboolean
++LibPinyinBopomofoEditor::moveCursorLeftByWord (void)
++{
++    if (G_UNLIKELY (m_cursor == 0))
++        return FALSE;
++
++    if (G_UNLIKELY (m_cursor > m_pinyin_len)) {
++        m_cursor = m_pinyin_len;
++        return TRUE;
++    }
++
++    const Pinyin & p = *m_pinyin.back ();
++    m_cursor -= p.len;
++    m_pinyin_len -= p.len;
++    m_pinyin.pop_back ();
++    update ();
++
++    return TRUE;
++}
++
++gboolean
++LibPinyinBopomofoEditor::moveCursorRightByWord (void)
++{
++    return moveCursorToEnd ();
++}
++
++gboolean
++LibPinyinBopomofoEditor::moveCursorToBegin (void)
++{
++    if (G_UNLIKELY (m_cursor == 0))
++        return FALSE;
++
++    m_cursor = 0;
++    update();
++
++    return TRUE;
++}
++
++gboolean
++LibPinyinBopomofoEditor::moveCursorToEnd (void)
++{
++    if (G_UNLIKELY (m_cursor == m_text.length ()))
++        return FALSE;
++
++    m_cursor = m_text.length ();
++    update();
++    return TRUE;
++}
++
++gboolean
++LibPinyinBopomofoEditor::processGuideKey (guint keyval, guint keycode,
++                                          guint modifiers)
++{
++    if (!m_config.guideKey ())
++        return FALSE;
++
++    if (G_UNLIKELY (cmshm_filter (modifiers) != 0))
++        return FALSE;
++
++    if (G_LIKELY (m_select_mode))
++        return FALSE;
++
++    if (G_UNLIKELY (keyval == IBUS_space)) {
++        m_select_mode = TRUE;
++        update ();
++        return TRUE;
++    }
++
++    return FALSE;
++}
++
++gboolean
++LibPinyinBopomofoEditor::processAuxiliarySelectKey
++(guint keyval, guint keycode, guint modifiers)
++{
++    if (G_UNLIKELY (cmshm_filter (modifiers) != 0))
++        return FALSE;
++
++    guint i;
++
++    switch (keyval) {
++    case IBUS_KP_0:
++        i = 9;
++        if (!m_config.auxiliarySelectKeyKP ())
++            return FALSE;
++        break;
++    case IBUS_KP_1 ... IBUS_KP_9:
++        i = keyval - IBUS_KP_1;
++        if (!m_config.auxiliarySelectKeyKP ())
++            return FALSE;
++        break;
++    case IBUS_F1 ... IBUS_F10:
++        i = keyval - IBUS_F1;
++        if (!m_config.auxiliarySelectKeyF ())
++            return FALSE;
++        break;
++    default:
++        return FALSE;
++    }
++
++    m_select_mode = TRUE;
++    selectCandidateInPage (i);
++
++    return TRUE;
++}
++
++gboolean
++LibPinyinBopomofoEditor::processSelectKey (guint keyval, guint keycode,
++                                           guint modifiers)
++{
++    if (G_UNLIKELY (!m_text))
++        return FALSE;
++
++    if (G_LIKELY (!m_select_mode && ((modifiers & IBUS_MOD1_MASK) == 0)))
++        return FALSE;
++
++    const gchar * pos = NULL;
++    const gchar * keys = bopomofo_select_keys[m_config.selectKeys ()];
++    for ( const gchar * p = keys; *p != NULL; ++p ) {
++        if ( *p == keyval )
++            pos = p;
++    }
++
++    if (pos == NULL)
++        return FALSE;
++
++    m_select_mode = TRUE;
++
++    guint i = pos - keys;
++    selectCandidateInPage (i);
++
++    return TRUE;
++}
++
++gboolean
++LibPinyinBopomofoEditor::processBopomofo (guint keyval, guint keycode,
++                                          guint modifiers)
++{
++    if (G_UNLIKELY (cmshm_filter (modifiers) != 0))
++        return m_text ? TRUE : FALSE;
++
++    if (keyvalToBopomofo (keyval) == BOPOMOFO_ZERO)
++        return FALSE;
++
++    m_select_mode = FALSE;
++
++    return insert (keyval);
++}
++
++gboolean
++LibPinyinBopomofoEditor::processKeyEvent (guint keyval, guint keycode,
++                                          guint modifiers)
++{
++    modifiers &= (IBUS_SHIFT_MASK |
++                  IBUS_CONTROL_MASK |
++                  IBUS_MOD1_MASK |
++                  IBUS_SUPER_MASK |
++                  IBUS_HYPER_MASK |
++                  IBUS_META_MASK |
++                  IBUS_LOCK_MASK);
++
++    if (G_UNLIKELY (processGuideKey (keyval, keycode, modifiers)))
++        return TRUE;
++    if (G_UNLIKELY (processSelectKey (keyval, keycode, modifiers)))
++        return TRUE;
++    if (G_UNLIKELY (processAuxiliarySelectKey (keyval, keycode,
++                                               modifiers)))
++        return TRUE;
++    if (G_LIKELY (processBopomofo (keyval, keycode, modifiers)))
++        return TRUE;
++
++    switch (keyval) {
++    case IBUS_space:
++        m_select_mode = TRUE;
++        return processSpace (keyval, keycode, modifiers);
++
++    case IBUS_Up:        case IBUS_KP_Up:
++    case IBUS_Down:      case IBUS_KP_Down:
++    case IBUS_Page_Up:   case IBUS_KP_Page_Up:
++    case IBUS_Page_Down: case IBUS_KP_Page_Down:
++    case IBUS_Tab:
++        m_select_mode = TRUE;
++        return LibPinyinPhoneticEditor::processFunctionKey
++            (keyval, keycode, modifiers);
++
++    case IBUS_BackSpace:
++    case IBUS_Delete:    case IBUS_KP_Delete:
++    case IBUS_Left:      case IBUS_KP_Left:
++    case IBUS_Right:     case IBUS_KP_Right:
++    case IBUS_Home:      case IBUS_KP_Home:
++    case IBUS_End:       case IBUS_KP_End:
++        m_select_mode = FALSE;
++        return LibPinyinPhoneticEditor::processFunctionKey
++            (keyval, keycode, modifiers);
++
++    default:
++        return LibPinyinPhoneticEditor::processFunctionKey
++            (keyval, keycode, modifiers);
++    }
++    return FALSE;
++}
++
++gint
++LibPinyinBopomofoEditor::keyvalToBopomofo(gint ch)
++{
++    const gint keyboard = m_config.bopomofoKeyboardMapping ();    
++    const guint8 & keys[41][2] = bopomofo_keyboard[keyboard];
++    gint len = G_N_ELEMENTS (bopomofo_keyboard[keyboard]);
++
++    for ( size_t i = 0; i < len; ++i ) {
++        if ( keys[i][0] == ch )
++            return keys[i][1];
++    }
++
++    return BOPOMOFO_ZERO;
++}
+diff --git a/src/PYPBopomofoEditor.h b/src/PYPBopomofoEditor.h
+new file mode 100644
+index 0000000..bcbf85d
+--- /dev/null
++++ b/src/PYPBopomofoEditor.h
+@@ -0,0 +1,77 @@
++/* vim:set et ts=4 sts=4:
++ *
++ * ibus-pinyin - The Chinese PinYin engine for IBus
++ *
++ * Copyright (c) 2011 Peng Wu <alexepico at gmail.com>
++ *
++ * 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.
++ */
++#ifndef __PY_LIB_PINYIN_BOPOMOFO_EDITOR_H_
++#define __PY_LIB_PINYIN_BOPOMOFO_EDITOR_H_
++
++#include "PYPPhoneticEditor.h"
++
++namespace PY {
++
++class Config;
++
++#define MAX_PINYIN_LEN 64
++
++class LibPinyinBopomofoEditor : public LibPinyinPhoneticEditor {
++
++public:
++    LibPinyinBopomofoEditor (PinyinProperties & props, Config & config);
++    ~LibPinyinBopomofoEditor (void);
++
++protected:
++    String bopomofo;
++    gboolean m_select_mode;
++
++    gboolean processGuideKey (guint keyval, guint keycode, guint modifiers);
++    gboolean processAuxiliarySelectKey (guint keyval, guint keycode,
++                                        guint modifiers);
++    gboolean processSelectKey (guint keyval, guint keycode, guint modifiers);
++    gboolean processBopomofo (guint keyval, guint keycode, guint modifiers);
++    gboolean processKeyEvent (guint keyval, guint keycode, guint modifiers);
++
++    void updateAuxiliaryText ();
++    void updateLookupTable ();
++    void updatePreeditText ();
++
++    void update ();
++    void commit ();
++    void reset ();
++
++    gboolean insert (gint ch);
++    gint keyvalToBopomofo (gint ch);
++
++    gboolean removeCharBefore (void);
++    gboolean removeCharAfter (void);
++    gboolean removeWordBefore (void);
++    gboolean removeWordAfter (void);
++
++    gboolean moveCursorLeft (void);
++    gboolean moveCursorRight (void);
++    gboolean moveCursorLeftByWord (void);
++    gboolean moveCursorRightByWord (void);
++    gboolean moveCursorToBegin (void);
++    gboolean moveCursorToEnd (void);
++
++};
++
++};
++
++
++#endif
+-- 
+1.7.6.4
+
+
+From 5a59f456bb40ea381a8f39858a0a8d3f8e43b074 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Mon, 5 Sep 2011 17:13:31 +0800
+Subject: [PATCH 14/71] fixes compile
+
+---
+ src/Makefile.am          |    2 ++
+ src/PYPBopomofoEditor.cc |    9 ++++-----
+ src/PYPBopomofoEditor.h  |    2 ++
+ 3 files changed, 8 insertions(+), 5 deletions(-)
+
+diff --git a/src/Makefile.am b/src/Makefile.am
+index ddebb04..3065410 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -66,6 +66,7 @@ ibus_engine_pinyin_c_sources = \
+ 	PYSpecialPhraseTable.cc \
+ 	PYPPhoneticEditor.cc \
+ 	PYPPinyinEditor.cc \
++	PYPBopomofoEditor.cc \
+ 	$(NULL)
+ ibus_engine_pinyin_h_sources = \
+ 	PYBopomofo.h \
+@@ -111,6 +112,7 @@ ibus_engine_pinyin_h_sources = \
+ 	PYLibPinyin.h \
+ 	PYPPhoneticEditor.h \
+ 	PYPPinyinEditor.h \
++	PYPBopomofoEditor.h \
+ 	$(NULL)
+ 
+ if IBUS_BUILD_LUA_EXTENSION
+diff --git a/src/PYPBopomofoEditor.cc b/src/PYPBopomofoEditor.cc
+index 75c8ddc..cb64abd 100644
+--- a/src/PYPBopomofoEditor.cc
++++ b/src/PYPBopomofoEditor.cc
+@@ -274,7 +274,7 @@ LibPinyinBopomofoEditor::processSelectKey (guint keyval, guint keycode,
+ 
+     const gchar * pos = NULL;
+     const gchar * keys = bopomofo_select_keys[m_config.selectKeys ()];
+-    for ( const gchar * p = keys; *p != NULL; ++p ) {
++    for ( const gchar * p = keys; *p; ++p ) {
+         if ( *p == keyval )
+             pos = p;
+     }
+@@ -362,12 +362,11 @@ gint
+ LibPinyinBopomofoEditor::keyvalToBopomofo(gint ch)
+ {
+     const gint keyboard = m_config.bopomofoKeyboardMapping ();    
+-    const guint8 & keys[41][2] = bopomofo_keyboard[keyboard];
+     gint len = G_N_ELEMENTS (bopomofo_keyboard[keyboard]);
+ 
+-    for ( size_t i = 0; i < len; ++i ) {
+-        if ( keys[i][0] == ch )
+-            return keys[i][1];
++    for ( gint i = 0; i < len; ++i ) {
++        if ( bopomofo_keyboard[keyboard][i][0] == ch )
++            return bopomofo_keyboard[keyboard][i][1];
+     }
+ 
+     return BOPOMOFO_ZERO;
+diff --git a/src/PYPBopomofoEditor.h b/src/PYPBopomofoEditor.h
+index bcbf85d..f78375f 100644
+--- a/src/PYPBopomofoEditor.h
++++ b/src/PYPBopomofoEditor.h
+@@ -46,12 +46,14 @@ protected:
+     gboolean processBopomofo (guint keyval, guint keycode, guint modifiers);
+     gboolean processKeyEvent (guint keyval, guint keycode, guint modifiers);
+ 
++#if 0
+     void updateAuxiliaryText ();
+     void updateLookupTable ();
+     void updatePreeditText ();
+ 
+     void update ();
+     void commit ();
++#endif
+     void reset ();
+ 
+     gboolean insert (gint ch);
+-- 
+1.7.6.4
+
+
+From 2c724244d80e4d79385be7e0f5744b286c5b30a1 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Thu, 8 Sep 2011 15:13:17 +0800
+Subject: [PATCH 15/71] add libpinyin deps
+
+---
+ configure.ac            |    5 +++++
+ src/Makefile.am         |    2 ++
+ src/PYPPhoneticEditor.h |    4 ++++
+ 3 files changed, 11 insertions(+), 0 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index 6afc180..1e3394d 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -62,6 +62,11 @@ PKG_CHECK_MODULES(SQLITE, [
+ ])
+ AC_PATH_PROG(SQLITE3, sqlite3)
+ 
++# check libpinyin
++PKG_CHECK_MODULES(LIBPINYIN, [
++    libpinyin >= 0.2.0
++])
++
+ # check uuid
+ AC_CHECK_FUNCS([uuid_create], [], [
+     PKG_CHECK_MODULES(LIBUUID, uuid, [
+diff --git a/src/Makefile.am b/src/Makefile.am
+index 3065410..fd12e0b 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -134,6 +134,7 @@ ibus_engine_pinyin_SOURCES = \
+ ibus_engine_pinyin_CXXFLAGS = \
+ 	@IBUS_CFLAGS@ \
+ 	@SQLITE_CFLAGS@ \
++	@LIBPINYIN_CFLAGS@ \
+ 	@OPENCC_CFLAGS@ \
+ 	-DGETTEXT_PACKAGE=\"@GETTEXT_PACKAGE@\" \
+ 	-DPKGDATADIR=\"$(pkgdatadir)\" \
+@@ -153,6 +154,7 @@ endif
+ ibus_engine_pinyin_LDADD = \
+ 	@IBUS_LIBS@ \
+ 	@SQLITE_LIBS@ \
++	@LIBPINYIN_LIBS@ \
+ 	@OPENCC_LIBS@ \
+ 	$(NULL)
+ 
+diff --git a/src/PYPPhoneticEditor.h b/src/PYPPhoneticEditor.h
+index 3d64bc4..f222557 100644
+--- a/src/PYPPhoneticEditor.h
++++ b/src/PYPPhoneticEditor.h
+@@ -21,6 +21,7 @@
+ #ifndef __PY_LIB_PINYIN_BASE_EDITOR_H_
+ #define __PY_LIB_PINYIN_BASE_EDITOR_H_
+ 
++#include <pinyin.h>
+ #include "PYLookupTable.h"
+ #include "PYEditor.h"
+ #include "PYPinyinParser.h"
+@@ -81,6 +82,9 @@ protected:
+     String                      m_buffer;
+ 
+     /* use LibPinyinBackEnd here. */
++    CandidateConstraints m_constraints;
++    MatchResults m_match_results;
++
+     std::vector<std::string>    m_special_phrases;
+     std::string                 m_selected_special_phrase;
+ };
+-- 
+1.7.6.4
+
+
+From aa80dfa352b8657202c895062283d9e930735b14 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Thu, 8 Sep 2011 18:02:51 +0800
+Subject: [PATCH 16/71] begin to write libpinyin backend
+
+---
+ src/Makefile.am    |    1 +
+ src/PYLibPinyin.cc |   39 +++++++++++++++++++++++++++++++++++++++
+ src/PYLibPinyin.h  |    8 +++++++-
+ 3 files changed, 47 insertions(+), 1 deletions(-)
+ create mode 100644 src/PYLibPinyin.cc
+
+diff --git a/src/Makefile.am b/src/Makefile.am
+index fd12e0b..d70b36b 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -64,6 +64,7 @@ ibus_engine_pinyin_c_sources = \
+ 	PYDynamicSpecialPhrase.cc \
+ 	PYSpecialPhrase.cc \
+ 	PYSpecialPhraseTable.cc \
++	PYLibPinyin.cc \
+ 	PYPPhoneticEditor.cc \
+ 	PYPPinyinEditor.cc \
+ 	PYPBopomofoEditor.cc \
+diff --git a/src/PYLibPinyin.cc b/src/PYLibPinyin.cc
+new file mode 100644
+index 0000000..55ffb8b
+--- /dev/null
++++ b/src/PYLibPinyin.cc
+@@ -0,0 +1,39 @@
++/* vim:set et ts=4 sts=4:
++ *
++ * ibus-pinyin - The Chinese PinYin engine for IBus
++ *
++ * Copyright (c) 2011 Peng Wu <alexepico at gmail.com>
++ *
++ * 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 "PYLibPinyin.h"
++
++using namespace PY;
++
++std::unique_ptr<LibPinyinBackEnd> LibPinyinBackEnd::m_instance;
++
++static LibPinyinBackEnd libpinyin_backend;
++
++LibPinyinBackEnd::LibPinyinBackEnd(){
++    g_assert (NULL == m_instance.get ());
++    m_pinyin_context = pinyin_init("/usr/share/libpinyin/data", "../data");
++    m_instance.reset(this);
++}
++
++LibPinyinBackEnd::~LibPinyinBackEnd(){
++    pinyin_fini(m_pinyin_context);
++    m_instance = NULL;
++}
+diff --git a/src/PYLibPinyin.h b/src/PYLibPinyin.h
+index d3bc90c..c07b435 100644
+--- a/src/PYLibPinyin.h
++++ b/src/PYLibPinyin.h
+@@ -22,11 +22,17 @@
+ #ifndef __PY_LIB_PINYIN_H_
+ #define __PY_LIB_PINYIN_H_
+ 
+-typedef struct _pinyin_context_t pinyin_context_t;
++#include <memory>
++#include <pinyin.h>
+ 
+ namespace PY {
++
+ class LibPinyinBackEnd{
++
+ public:
++    LibPinyinBackEnd();
++    ~LibPinyinBackEnd();
++
+     /* use static initializer in C++. */
+     static LibPinyinBackEnd & instance (void) { return *m_instance; }
+ 
+-- 
+1.7.6.4
+
+
+From 1f6ff1c6791cf266fcff9ac2808f85d902ee4b5f Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Wed, 14 Sep 2011 17:49:47 +0800
+Subject: [PATCH 17/71] add set options to libpinyin back end
+
+---
+ src/PYLibPinyin.cc |   51 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ src/PYLibPinyin.h  |    5 +++++
+ 2 files changed, 56 insertions(+), 0 deletions(-)
+
+diff --git a/src/PYLibPinyin.cc b/src/PYLibPinyin.cc
+index 55ffb8b..36eaba3 100644
+--- a/src/PYLibPinyin.cc
++++ b/src/PYLibPinyin.cc
+@@ -20,6 +20,8 @@
+  */
+ 
+ #include "PYLibPinyin.h"
++#include "PYTypes.h"
++#include "PYConfig.h"
+ 
+ using namespace PY;
+ 
+@@ -37,3 +39,52 @@ LibPinyinBackEnd::~LibPinyinBackEnd(){
+     pinyin_fini(m_pinyin_context);
+     m_instance = NULL;
+ }
++
++/* Here are the fuzzy pinyin options conversion table. */
++static const struct {
++    guint ibus_pinyin_option;
++    PinyinAmbiguity libpinyin_option;    
++} fuzzy_options [] = {
++    /* fuzzy pinyin */
++    { PINYIN_FUZZY_C_CH,        PINYIN_AmbCiChi        },
++    { PINYIN_FUZZY_CH_C,        PINYIN_AmbChiCi        },
++    { PINYIN_FUZZY_Z_ZH,        PINYIN_AmbZiZhi        },
++    { PINYIN_FUZZY_ZH_Z,        PINYIN_AmbZhiZi        },
++    { PINYIN_FUZZY_S_SH,        PINYIN_AmbSiShi        },
++    { PINYIN_FUZZY_SH_S,        PINYIN_AmbShiSi        },
++    { PINYIN_FUZZY_L_N,         PINYIN_AmbLeNe         },
++    { PINYIN_FUZZY_N_L,         PINYIN_AmbNeLe         },
++    { PINYIN_FUZZY_F_H,         PINYIN_AmbFoHe         },
++    { PINYIN_FUZZY_H_F,         PINYIN_AmbHeFo         },
++    { PINYIN_FUZZY_L_R,         PINYIN_AmbLeRi         },
++    { PINYIN_FUZZY_R_L,         PINYIN_AmbRiLe         },
++    { PINYIN_FUZZY_K_G,         PINYIN_AmbKeGe         },
++    { PINYIN_FUZZY_G_K,         PINYIN_AmbGeKe         },
++    { PINYIN_FUZZY_AN_ANG,      PINYIN_AmbAnAng        },
++    { PINYIN_FUZZY_ANG_AN,      PINYIN_AmbAngAn        },
++    { PINYIN_FUZZY_EN_ENG,      PINYIN_AmbEnEng        },
++    { PINYIN_FUZZY_ENG_EN,      PINYIN_AmbEngEn        },
++    { PINYIN_FUZZY_IN_ING,      PINYIN_AmbInIng        },
++    { PINYIN_FUZZY_ING_IN,      PINYIN_AmbIngIn        }
++};
++
++gboolean
++LibPinyinBackEnd::setPinyinOptions (Config * config)
++{
++    guint option = config->option ();
++    PinyinCustomSettings custom;
++
++    custom.set_use_incomplete (option & PINYIN_INCOMPLETE_PINYIN);
++    custom.set_use_ambiguities (PINYIN_AmbAny, false);
++
++    /* copy values */
++    for (guint i = 0; i < G_N_ELEMENTS (fuzzy_options); i++) {
++        if ( option & fuzzy_options[i].ibus_pinyin_option )
++            custom.set_use_ambiguities
++                (fuzzy_options[i].libpinyin_option, true);
++    }
++
++    pinyin_set_options(m_pinyin_context, &custom);
++
++    return TRUE;
++}
+diff --git a/src/PYLibPinyin.h b/src/PYLibPinyin.h
+index c07b435..83aa1fc 100644
+--- a/src/PYLibPinyin.h
++++ b/src/PYLibPinyin.h
+@@ -27,12 +27,16 @@
+ 
+ namespace PY {
+ 
++class Config;
++
+ class LibPinyinBackEnd{
+ 
+ public:
+     LibPinyinBackEnd();
+     ~LibPinyinBackEnd();
+ 
++    gboolean setPinyinOptions(Config *config);
++
+     /* use static initializer in C++. */
+     static LibPinyinBackEnd & instance (void) { return *m_instance; }
+ 
+@@ -42,6 +46,7 @@ private:
+ private:
+     static std::unique_ptr<LibPinyinBackEnd> m_instance;
+ };
++
+ };
+ 
+ #endif
+-- 
+1.7.6.4
+
+
+From 7bb6c26be96489e919736eb719abafcf11796e15 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Thu, 15 Sep 2011 15:19:49 +0800
+Subject: [PATCH 18/71] remove special phrase
+
+---
+ src/PYPPhoneticEditor.cc |   41 -----------------------------------------
+ src/PYPPhoneticEditor.h  |    7 +------
+ 2 files changed, 1 insertions(+), 47 deletions(-)
+
+diff --git a/src/PYPPhoneticEditor.cc b/src/PYPPhoneticEditor.cc
+index ef9a02d..fc4aee2 100644
+--- a/src/PYPPhoneticEditor.cc
++++ b/src/PYPPhoneticEditor.cc
+@@ -161,27 +161,6 @@ LibPinyinPhoneticEditor::processKeyEvent (guint keyval, guint keycode, guint mod
+     return FALSE;
+ }
+ 
+-gboolean
+-LibPinyinPhoneticEditor::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;
+-
+-    /* Note: change behavior to match the entire m_text,
+-     *         instead of partial m_text.
+-     */
+-    SpecialPhraseTable::instance ().lookup
+-        (m_text, m_special_phrases);
+-
+-    return size != m_special_phrases.size() || size != 0;
+-}
+-
+ void
+ LibPinyinPhoneticEditor::updateLookupTableFast (void)
+ {
+@@ -204,9 +183,6 @@ LibPinyinPhoneticEditor::updateLookupTable (void)
+ gboolean
+ LibPinyinPhoneticEditor::fillLookupTableByPage (void)
+ {
+-    if (!m_selected_special_phrase.empty ()) {
+-        return FALSE;
+-    }
+ 
+     guint filled_nr = m_lookup_table.size ();
+     guint page_size = m_lookup_table.pageSize ();
+@@ -273,8 +249,6 @@ LibPinyinPhoneticEditor::reset (void)
+     m_pinyin.clear ();
+     m_pinyin_len = 0;
+     m_lookup_table.clear ();
+-    m_special_phrases.clear ();
+-    m_selected_special_phrase.clear ();
+ 
+     Editor::reset ();
+ }
+@@ -298,21 +272,6 @@ gboolean
+ LibPinyinPhoneticEditor::selectCandidate (guint i)
+ {
+ 
+-    if (i < m_special_phrases.size ()) {
+-        /* select a special phrase */
+-        m_selected_special_phrase = m_special_phrases[i];
+-        if (m_cursor == m_text.size()) {
+-            m_buffer = m_selected_special_phrase;
+-            reset ();
+-            commit ((const gchar *)m_buffer);
+-        } else {
+-            updateSpecialPhrases ();
+-            update ();
+-        }
+-        return TRUE;
+-    }
+-
+-    i -= m_special_phrases.size ();
+     /* TODO: deal with normal candidates selection here by libpinyin. */
+     g_assert (FALSE);
+ }
+diff --git a/src/PYPPhoneticEditor.h b/src/PYPPhoneticEditor.h
+index f222557..f7a3704 100644
+--- a/src/PYPPhoneticEditor.h
++++ b/src/PYPPhoneticEditor.h
+@@ -51,7 +51,6 @@ public:
+ 
+ protected:
+ 
+-    gboolean updateSpecialPhrases ();
+     gboolean selectCandidate (guint i);
+     gboolean selectCandidateInPage (guint i);
+ 
+@@ -82,11 +81,7 @@ protected:
+     String                      m_buffer;
+ 
+     /* use LibPinyinBackEnd here. */
+-    CandidateConstraints m_constraints;
+-    MatchResults m_match_results;
+-
+-    std::vector<std::string>    m_special_phrases;
+-    std::string                 m_selected_special_phrase;
++    pinyin_instance_t           *m_instance;
+ };
+ 
+ };
+-- 
+1.7.6.4
+
+
+From c9a83029d574da3de06bc8d3b3766919acd68c5c Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Fri, 16 Sep 2011 15:43:35 +0800
+Subject: [PATCH 19/71] refactor libpinyin phonetic editor
+
+---
+ src/PYPPhoneticEditor.cc |   59 +++++++++++++++++++++++++++++++++++++++------
+ src/PYPPhoneticEditor.h  |    6 +++-
+ 2 files changed, 55 insertions(+), 10 deletions(-)
+
+diff --git a/src/PYPPhoneticEditor.cc b/src/PYPPhoneticEditor.cc
+index fc4aee2..86ee42b 100644
+--- a/src/PYPPhoneticEditor.cc
++++ b/src/PYPPhoneticEditor.cc
+@@ -29,8 +29,8 @@ using namespace PY;
+ LibPinyinPhoneticEditor::LibPinyinPhoneticEditor (PinyinProperties &props,
+                                                   Config &config):
+     Editor (props, config),
+-    m_pinyin (MAX_PHRASE_LEN),
+-    m_pinyin_len (0),
++    m_pinyins (MAX_PHRASE_LEN),
++    m_pinyin_cursor (0),
+     m_lookup_table (m_config.pageSize ())
+ {
+ }
+@@ -188,7 +188,34 @@ LibPinyinPhoneticEditor::fillLookupTableByPage (void)
+     guint page_size = m_lookup_table.pageSize ();
+ 
+     /* fill lookup table by libpinyin get candidates. */
+-    g_assert(FALSE);
++    guint need_nr = MIN (page_size, m_candidates->len - filled_nr);
++    g_assert (need_nr >=0);
++    if (need_nr == 0)
++        return FALSE;
++
++    for (guint i = filled_nr; i < filled_nr + need_nr; i++) {
++        if (G_LIKELY (m_props.modeSimp ())) { /* Simplified Chinese */
++            phrase_token_t *token = &g_array_index
++                (m_candidates, phrase_token_t, i);
++            char *word = NULL;
++            pinyin_translate_token(m_instance, *token, &word);
++            Text text (word);
++            m_lookup_table.appendCandidate(text);
++            g_free(word);
++        } else { /* Traditional Chinese */
++            m_buffer.truncate (0);
++            phrase_token_t *token = &g_array_index
++                (m_candidates, phrase_token_t, i);
++            char *word = NULL;
++            pinyin_translate_token(m_instance, *token, &word);
++            SimpTradConverter::simpToTrad (word, m_buffer);
++            Text text (m_buffer);
++            m_lookup_table.appendCandidate (text);
++            g_free(word);
++        }
++    }
++
++    return TRUE;
+ }
+ 
+ void
+@@ -246,8 +273,8 @@ LibPinyinPhoneticEditor::candidateClicked (guint index, guint button, guint stat
+ void
+ LibPinyinPhoneticEditor::reset (void)
+ {
+-    m_pinyin.clear ();
+-    m_pinyin_len = 0;
++    m_pinyins.clear ();
++    m_pinyin_cursor = 0;
+     m_lookup_table.clear ();
+ 
+     Editor::reset ();
+@@ -268,12 +295,28 @@ LibPinyinPhoneticEditor::commit (const gchar *str)
+     commitText (text);
+ }
+ 
++void
++LibPinyinPhoneticEditor::updatePinyinCursor ()
++{
++    /* Translate cursor position to pinyin position. */
++    m_pinyin_cursor = MIN (m_pinyin_cursor, m_pinyins.size ());
++    PinyinArray::const_iterator iter = m_pinyins.begin ();
++    for ( ; iter != m_pinyins.end (); ++iter) {
++        guint end = iter->begin + iter->len;
++        if ( iter->begin <= m_cursor && m_cursor < end )
++            m_pinyin_cursor = iter - m_pinyins.begin ();
++    }
++    m_pinyin_cursor = MAX (m_pinyin_cursor, 0);
++}
++
+ gboolean
+ LibPinyinPhoneticEditor::selectCandidate (guint i)
+ {
+-
+-    /* TODO: deal with normal candidates selection here by libpinyin. */
+-    g_assert (FALSE);
++    /* Prolog: assume updatePinyinCursor is called before. */
++    /* NOTE: deal with normal candidates selection here by libpinyin. */
++    phrase_token_t *token = &g_array_index (m_candidates, phrase_token_t, i);
++    pinyin_choose_candidate(m_instance, m_pinyin_cursor, *token);
++    return TRUE;
+ }
+ 
+ gboolean
+diff --git a/src/PYPPhoneticEditor.h b/src/PYPPhoneticEditor.h
+index f7a3704..a3b03ff 100644
+--- a/src/PYPPhoneticEditor.h
++++ b/src/PYPPhoneticEditor.h
+@@ -55,6 +55,7 @@ protected:
+     gboolean selectCandidateInPage (guint i);
+ 
+     void commit (const gchar *str);
++    void updatePinyinCursor ();
+ 
+     /* inline functions */
+ 
+@@ -75,13 +76,14 @@ protected:
+     virtual void updatePreeditText (void) = 0;
+ 
+     /* varibles */
+-    PinyinArray                 m_pinyin;
+-    guint                       m_pinyin_len;
++    PinyinArray                 m_pinyins;
++    guint                       m_pinyin_cursor;
+     LookupTable                 m_lookup_table;
+     String                      m_buffer;
+ 
+     /* use LibPinyinBackEnd here. */
+     pinyin_instance_t           *m_instance;
++    TokenVector                 m_candidates;
+ };
+ 
+ };
+-- 
+1.7.6.4
+
+
+From 0afa90502dac19f65253c3bd6d6dd6b97f403ec7 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Fri, 16 Sep 2011 15:51:12 +0800
+Subject: [PATCH 20/71] clean up libpinyin bopomofo editor
+
+---
+ src/PYPBopomofoEditor.cc |   39 +++++++++++++--------------------------
+ 1 files changed, 13 insertions(+), 26 deletions(-)
+
+diff --git a/src/PYPBopomofoEditor.cc b/src/PYPBopomofoEditor.cc
+index cb64abd..35c9ed2 100644
+--- a/src/PYPBopomofoEditor.cc
++++ b/src/PYPBopomofoEditor.cc
+@@ -103,19 +103,8 @@ LibPinyinBopomofoEditor::removeWordBefore (void)
+     if (G_UNLIKELY (m_cursor == 0))
+         return FALSE;
+ 
+-    guint cursor;
+-    if (G_UNLIKELY (m_cursor > m_pinyin_len)) {
+-        cursor = m_pinyin_len;
+-    } else {
+-        const Pinyin & p = *m_pinyin.back ();
+-        cursor = m_cursor - p.len;
+-        m_pinyin_len -= p.len;
+-        m_pinyin.pop_back ();
+-    }
+-
+-    m_text.erase (cursor, m_cursor - cursor);
+-    m_cursor = cursor;
+-    update();
++    /* TODO: to be implemented. */
++    g_assert(FALSE);
+ 
+     return TRUE;
+ }
+@@ -127,8 +116,8 @@ LibPinyinBopomofoEditor::removeWordAfter (void)
+         return FALSE;
+ 
+     /* TODO: remove one word instead of the sentence. */
+-    m_text.erase (m_cursor, -1);
+-    update ();
++    g_assert(FALSE);
++
+     return TRUE;
+ }
+ 
+@@ -162,16 +151,8 @@ LibPinyinBopomofoEditor::moveCursorLeftByWord (void)
+     if (G_UNLIKELY (m_cursor == 0))
+         return FALSE;
+ 
+-    if (G_UNLIKELY (m_cursor > m_pinyin_len)) {
+-        m_cursor = m_pinyin_len;
+-        return TRUE;
+-    }
+-
+-    const Pinyin & p = *m_pinyin.back ();
+-    m_cursor -= p.len;
+-    m_pinyin_len -= p.len;
+-    m_pinyin.pop_back ();
+-    update ();
++    /* TODO: to be implemented. */
++    g_assert(FALSE);
+ 
+     return TRUE;
+ }
+@@ -179,7 +160,13 @@ LibPinyinBopomofoEditor::moveCursorLeftByWord (void)
+ gboolean
+ LibPinyinBopomofoEditor::moveCursorRightByWord (void)
+ {
+-    return moveCursorToEnd ();
++    if (G_UNLIKELY (m_cursor == m_text.length ()))
++        return FALSE;
++
++    /* TODO: to be implemented. */
++    g_assert(FALSE);
++
++    return TRUE;
+ }
+ 
+ gboolean
+-- 
+1.7.6.4
+
+
+From 5d0466f732e7520851edb8145c348b29c8bea252 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Fri, 16 Sep 2011 17:31:56 +0800
+Subject: [PATCH 21/71] add m_pinyin_len back
+
+---
+ src/PYPPhoneticEditor.cc |   20 +++++++++++---------
+ src/PYPPhoneticEditor.h  |    4 ++--
+ 2 files changed, 13 insertions(+), 11 deletions(-)
+
+diff --git a/src/PYPPhoneticEditor.cc b/src/PYPPhoneticEditor.cc
+index 86ee42b..a26ce85 100644
+--- a/src/PYPPhoneticEditor.cc
++++ b/src/PYPPhoneticEditor.cc
+@@ -30,7 +30,7 @@ LibPinyinPhoneticEditor::LibPinyinPhoneticEditor (PinyinProperties &props,
+                                                   Config &config):
+     Editor (props, config),
+     m_pinyins (MAX_PHRASE_LEN),
+-    m_pinyin_cursor (0),
++    m_pinyin_len (0),
+     m_lookup_table (m_config.pageSize ())
+ {
+ }
+@@ -274,7 +274,7 @@ void
+ LibPinyinPhoneticEditor::reset (void)
+ {
+     m_pinyins.clear ();
+-    m_pinyin_cursor = 0;
++    m_pinyin_len = 0;
+     m_lookup_table.clear ();
+ 
+     Editor::reset ();
+@@ -295,27 +295,29 @@ LibPinyinPhoneticEditor::commit (const gchar *str)
+     commitText (text);
+ }
+ 
+-void
+-LibPinyinPhoneticEditor::updatePinyinCursor ()
++guint
++LibPinyinPhoneticEditor::getPinyinCursor ()
+ {
+     /* Translate cursor position to pinyin position. */
+-    m_pinyin_cursor = MIN (m_pinyin_cursor, m_pinyins.size ());
++    guint pinyin_cursor = m_pinyins.size ();
+     PinyinArray::const_iterator iter = m_pinyins.begin ();
+     for ( ; iter != m_pinyins.end (); ++iter) {
+         guint end = iter->begin + iter->len;
+         if ( iter->begin <= m_cursor && m_cursor < end )
+-            m_pinyin_cursor = iter - m_pinyins.begin ();
++            pinyin_cursor = iter - m_pinyins.begin ();
+     }
+-    m_pinyin_cursor = MAX (m_pinyin_cursor, 0);
++    g_assert (pinyin_cursor >= 0);
++    return pinyin_cursor;
+ }
+ 
+ gboolean
+ LibPinyinPhoneticEditor::selectCandidate (guint i)
+ {
+-    /* Prolog: assume updatePinyinCursor is called before. */
++    guint pinyin_cursor = getPinyinCursor ();
++
+     /* NOTE: deal with normal candidates selection here by libpinyin. */
+     phrase_token_t *token = &g_array_index (m_candidates, phrase_token_t, i);
+-    pinyin_choose_candidate(m_instance, m_pinyin_cursor, *token);
++    pinyin_choose_candidate(m_instance, pinyin_cursor, *token);
+     return TRUE;
+ }
+ 
+diff --git a/src/PYPPhoneticEditor.h b/src/PYPPhoneticEditor.h
+index a3b03ff..32a5245 100644
+--- a/src/PYPPhoneticEditor.h
++++ b/src/PYPPhoneticEditor.h
+@@ -55,7 +55,7 @@ protected:
+     gboolean selectCandidateInPage (guint i);
+ 
+     void commit (const gchar *str);
+-    void updatePinyinCursor ();
++    guint getPinyinCursor ();
+ 
+     /* inline functions */
+ 
+@@ -77,7 +77,7 @@ protected:
+ 
+     /* varibles */
+     PinyinArray                 m_pinyins;
+-    guint                       m_pinyin_cursor;
++    guint                       m_pinyin_len;
+     LookupTable                 m_lookup_table;
+     String                      m_buffer;
+ 
+-- 
+1.7.6.4
+
+
+From 325056f0f43e86da5621ac04d5261faaabe5041c Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Mon, 19 Sep 2011 16:10:48 +0800
+Subject: [PATCH 22/71] write pinyin editor in progress
+
+---
+ src/PYPPhoneticEditor.h |    2 +-
+ src/PYPPinyinEditor.cc  |   79 +++++++++++++++++++++++++++++++++++++++++++++--
+ 2 files changed, 77 insertions(+), 4 deletions(-)
+
+diff --git a/src/PYPPhoneticEditor.h b/src/PYPPhoneticEditor.h
+index 32a5245..428f17b 100644
+--- a/src/PYPPhoneticEditor.h
++++ b/src/PYPPhoneticEditor.h
+@@ -25,7 +25,7 @@
+ #include "PYLookupTable.h"
+ #include "PYEditor.h"
+ #include "PYPinyinParser.h"
+-#include "PYSpecialPhraseTable.h"
++
+ 
+ namespace PY {
+ 
+diff --git a/src/PYPPinyinEditor.cc b/src/PYPPinyinEditor.cc
+index a78544d..a435b82 100644
+--- a/src/PYPPinyinEditor.cc
++++ b/src/PYPPinyinEditor.cc
+@@ -200,19 +200,92 @@ LibPinyinPinyinEditor::processKeyEvent (guint keyval, guint keycode,
+ void
+ LibPinyinPinyinEditor::commit ()
+ {
+-    g_assert (FALSE);
++
++    if (G_UNLIKELY (m_buffer.empty ()))
++        return;
++
++    m_buffer.clear ();
++
++    /* sentence candidate */
++    char *tmp = NULL;
++    pinyin_get_sentence(m_instance, &tmp);
++    m_buffer << tmp;
++    g_free (tmp);
++    tmp = NULL;
++
++    /* text after pinyin */
++    const gchar *p = m_text.c_str() + m_pinyin_len;
++    if (G_UNLIKELY (m_props.modeFull ())) {
++        while (*p != '\0') {
++            m_buffer.appendUnichar (HalfFullConverter::toFull (*p++));
++        }
++    } else {
++        m_buffer << p;
++    }
++
++    pinyin_train(m_instance);
++    LibPinyinPhoneticEditor::commit ((const gchar *)m_buffer);
++    reset();
+ }
+ 
+ void
+ LibPinyinPinyinEditor::updatePreeditText ()
+ {
+-    g_assert (FALSE);
++    /* preedit text = guessed sentence + un-parsed pinyin text */
++    if (G_UNLIKELY (m_text.empty ())) {
++        hidePreeditText ();
++        return;
++    }
++
++    m_buffer.clear ();
++    char *tmp = NULL;
++    pinyin_get_sentence(m_instance, &tmp);
++    if (m_props.modeSimp ()) {
++        m_buffer<<tmp;
++    } else {
++        SimpTradConverter::simpToTrad (tmp, m_buffer);
++    }
++    g_free (tmp);
++    tmp = NULL;
++
++    /* append rest text */
++    const gchar *p = m_text.c_str () + m_pinyin_len;
++    m_buffer << p;
++
++    StaticText preedit_text (m_buffer);
++    /* underline */
++    preedit_text.appendAttribute (IBUS_ATTR_TYPE_UNDERLINE, IBUS_ATTR_UNDERLINE_SINGLE, 0, -1);
++
++    guint pinyin_cursor = getPinyinCursor ();
++    Editor::updatePreeditText (preedit_text, pinyin_cursor, TRUE);
+ }
+ 
+ void
+ LibPinyinPinyinEditor::updateAuxiliaryText ()
+ {
+-    g_assert (FALSE);
++    if (G_UNLIKELY (m_text.empty ())) {
++        hideAuxiliaryText ();
++        return;
++    }
++
++    m_buffer.clear ();
++
++    /* Note: cursor handling is defered to full/double pinyin editors. */
++    guint pinyin_cursor = getPinyinCursor ();
++    for (guint i = 0; i < m_pinyins.size (); ++i) {
++        if (G_LIKELY (i))
++            m_buffer << ' ';
++        const Pinyin *pinyin = m_pinyins[i];
++        m_buffer << pinyin->sheng
++                 << pinyin->yun;
++    }
++
++    /* append rest text */
++    const gchar * p = m_text.c_str() + m_pinyin_len;
++    m_buffer << p;
++
++    StaticText aux_text (m_buffer);
++    Editor::updateAuxiliaryText (aux_text, TRUE);
+ }
+ 
+ void
+-- 
+1.7.6.4
+
+
+From 6cee400f75eeb9d977cb3bb64df8dc282ab31aa7 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Mon, 19 Sep 2011 16:26:42 +0800
+Subject: [PATCH 23/71] begin to write libpinyin full pinyin editor
+
+---
+ src/Makefile.am            |    1 +
+ src/PYPFullPinyinEditor.cc |   64 ++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 65 insertions(+), 0 deletions(-)
+ create mode 100644 src/PYPFullPinyinEditor.cc
+
+diff --git a/src/Makefile.am b/src/Makefile.am
+index d70b36b..aeaaf89 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -67,6 +67,7 @@ ibus_engine_pinyin_c_sources = \
+ 	PYLibPinyin.cc \
+ 	PYPPhoneticEditor.cc \
+ 	PYPPinyinEditor.cc \
++	PYPFullPinyinEditor.cc \
+ 	PYPBopomofoEditor.cc \
+ 	$(NULL)
+ ibus_engine_pinyin_h_sources = \
+diff --git a/src/PYPFullPinyinEditor.cc b/src/PYPFullPinyinEditor.cc
+new file mode 100644
+index 0000000..9712d97
+--- /dev/null
++++ b/src/PYPFullPinyinEditor.cc
+@@ -0,0 +1,64 @@
++/* vim:set et ts=4 sts=4:
++ *
++ * ibus-pinyin - The Chinese PinYin engine for IBus
++ *
++ * Copyright (c) 2011 Peng Wu <alexepico at gmail.com>
++ *
++ * 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 "PYPFullPinyinEditor.h"
++#include "PYConfig.h"
++
++using namespace PY;
++
++LibPinyinFullPinyinEditor::LibPinyinFullPinyinEditor
++(PinyinProperties & props, Config & config)
++    : LibPinyinPinyinEditor (props, config)
++{
++}
++
++LibPinyinFullPinyinEditor::~LibPinyinFullPinyinEditor (void)
++{
++}
++
++void
++LibPinyinFullPinyinEditor::reset (void)
++{
++    LibPinyinPinyinEditor::reset ();
++}
++
++gboolean
++LibPinyinFullPinyinEditor::insert (gint ch)
++{
++    /* is full */
++    if (G_UNLIKELY (m_text.length () >= MAX_PINYIN_LEN))
++        return TRUE;
++
++    m_text.insert (m_cursor++, ch);
++
++    updatePinyin ();
++    update ();
++    return TRUE;
++}
++
++gboolean
++LibPinyinFullPinyinEditor::processKeyEvent (guint keyval,
++                                            guint keycode,
++                                            guint modifiers)
++{
++    return LibPinyinPinyinEditor::processKeyEvent (keyval, keycode, modifiers);
++}
++
+-- 
+1.7.6.4
+
+
+From b50a6e074f608f640afb074231ed643240bf26b3 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Tue, 20 Sep 2011 13:52:05 +0800
+Subject: [PATCH 24/71] write update pinyin
+
+---
+ src/PYPFullPinyinEditor.cc |   31 +++++++++++++++++++++++++++++++
+ src/PYPFullPinyinEditor.h  |    2 ++
+ 2 files changed, 33 insertions(+), 0 deletions(-)
+
+diff --git a/src/PYPFullPinyinEditor.cc b/src/PYPFullPinyinEditor.cc
+index 9712d97..5194ef8 100644
+--- a/src/PYPFullPinyinEditor.cc
++++ b/src/PYPFullPinyinEditor.cc
+@@ -62,3 +62,34 @@ LibPinyinFullPinyinEditor::processKeyEvent (guint keyval,
+     return LibPinyinPinyinEditor::processKeyEvent (keyval, keycode, modifiers);
+ }
+ 
++void
++LibPinyinFullPinyinEditor::updatePinyin (void)
++{
++    if (G_UNLIKELY (m_text.empty ())) {
++        m_pinyins.clear ();
++        m_pinyin_len = 0;
++        return;
++    }
++
++    m_pinyin_len = PinyinParser::parse (m_text,               // text
++                                        m_text.length (),     // text length
++                                        m_config.option (),   // option
++                                        m_pinyins,            // result
++                                        MAX_PHRASE_LEN);      // max result length
++
++    /* propagate to libpinyin */
++    g_array_set_size (m_instance->m_pinyin_keys, 0);
++    g_array_set_size (m_instance->m_pinyin_poses, 0);
++
++    PinyinKey key; PinyinKeyPos pos;
++    PinyinArray::const_iterator iter = m_pinyins.begin ();
++    for ( ; iter != m_pinyins.end (); ++iter ) {
++        PinyinSegment py = *iter;
++        pinyin_parse_full_pinyin (m_instance, py.pinyin->text, &key);
++        pos.set_pos (py.begin); pos.set_length (py.len);
++        g_array_append_val(m_instance->m_pinyin_keys, key);
++        g_array_append_val(m_instance->m_pinyin_poses, pos);
++    }
++
++    pinyin_guess_sentence(m_instance);
++}
+diff --git a/src/PYPFullPinyinEditor.h b/src/PYPFullPinyinEditor.h
+index a6e74c4..afb52d5 100644
+--- a/src/PYPFullPinyinEditor.h
++++ b/src/PYPFullPinyinEditor.h
+@@ -52,6 +52,8 @@ public:
+ 
+ protected:
+     /* TODO: to be implemented. */
++    void updatePinyin (void);
++
+ };
+ 
+ };
+-- 
+1.7.6.4
+
+
+From 3ceb1022d20885ed032a3b0275a48fe8cf96182d Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Tue, 20 Sep 2011 16:12:46 +0800
+Subject: [PATCH 25/71] add char edit
+
+---
+ src/PYPFullPinyinEditor.cc |   39 +++++++++++++++++++++++++++++++++++++++
+ 1 files changed, 39 insertions(+), 0 deletions(-)
+
+diff --git a/src/PYPFullPinyinEditor.cc b/src/PYPFullPinyinEditor.cc
+index 5194ef8..2b8babc 100644
+--- a/src/PYPFullPinyinEditor.cc
++++ b/src/PYPFullPinyinEditor.cc
+@@ -55,6 +55,45 @@ LibPinyinFullPinyinEditor::insert (gint ch)
+ }
+ 
+ gboolean
++LibPinyinFullPinyinEditor::removeCharBefore (void)
++{
++    if (G_UNLIKELY (m_cursor == 0))
++        return FALSE;
++
++    m_cursor --;
++    m_text.erase (m_cursor, 1);
++
++    updatePinyin ();
++    update ();
++
++    return TRUE;
++}
++
++gboolean
++LibPinyinFullPinyinEditor::removeCharAfter (void)
++{
++    if (G_UNLIKELY (m_cursor == m_text.length ()))
++        return FALSE;
++
++    m_text.erase (m_cursor, 1);
++
++    updatePinyin ();
++    update ();
++
++    return TRUE;
++}
++
++gboolean
++LibPinyinFullPinyinEditor::removeWordBefore (void)
++{
++    if (G_UNLIKELY (m_cursor == 0))
++        return FALSE;
++
++    /* TODO: to be implemented. */
++    g_assert (FALSE);
++}
++
++gboolean
+ LibPinyinFullPinyinEditor::processKeyEvent (guint keyval,
+                                             guint keycode,
+                                             guint modifiers)
+-- 
+1.7.6.4
+
+
+From 5ccaad1bdee85c6762ddfbf52bba6e8e2f82fd0a Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Wed, 21 Sep 2011 10:14:49 +0800
+Subject: [PATCH 26/71] write full pinyin editor in progress
+
+---
+ src/PYPFullPinyinEditor.cc |  131 +++++++++++++++++++++++++++++++++++++++++++-
+ 1 files changed, 129 insertions(+), 2 deletions(-)
+
+diff --git a/src/PYPFullPinyinEditor.cc b/src/PYPFullPinyinEditor.cc
+index 2b8babc..7e764c7 100644
+--- a/src/PYPFullPinyinEditor.cc
++++ b/src/PYPFullPinyinEditor.cc
+@@ -89,8 +89,135 @@ LibPinyinFullPinyinEditor::removeWordBefore (void)
+     if (G_UNLIKELY (m_cursor == 0))
+         return FALSE;
+ 
+-    /* TODO: to be implemented. */
+-    g_assert (FALSE);
++    guint cursor;
++
++    if (G_UNLIKELY (m_cursor > m_pinyin_len)) {
++        cursor = m_pinyin_len;
++    } else {
++        guint pinyin_cursor = getPinyinCursor ();
++        cursor = m_pinyins[pinyin_cursor].begin;
++        /* cursor at the begin of one pinyin */
++        g_return_val_if_fail (pinyin_cursor > 0, FALSE);
++        if ( cursor == m_cursor)
++            cursor = m_pinyins[pinyin_cursor - 1].begin;
++    }
++
++    m_text.erase (cursor, m_cursor - cursor);
++    m_cursor = cursor;
++    updatePinyin ();
++    update ();
++    return TRUE;
++}
++
++gboolean
++LibPinyinFullPinyinEditor::removeWordAfter (void)
++{
++    if (G_UNLIKELY (m_cursor == m_text.length ()))
++        return FALSE;
++
++    guint cursor;
++
++    if (G_UNLIKELY (m_cursor > m_pinyin_len)) {
++        cursor = m_text.length ();
++    } else {
++        guint pinyin_cursor = getPinyinCursor ();
++        PinyinSegment py = m_pinyins[pinyin_cursor];
++        cursor = py.begin + py.len;
++    }
++
++    m_text.erase (m_cursor, cursor - m_cursor);
++    updatePinyin ();
++    update ();
++    return TRUE;
++}
++
++gboolean
++LibPinyinFullPinyinEditor::moveCursorLeft (void)
++{
++    if (G_UNLIKELY (m_cursor == 0))
++        return FALSE;
++
++    m_cursor --;
++    update ();
++    return TRUE;
++}
++
++gboolean
++LibPinyinFullPinyinEditor::moveCursorRight (void)
++{
++    if (G_UNLIKELY (m_cursor == m_text.length ()))
++        return FALSE;
++
++    m_cursor ++;
++    update ();
++    return TRUE;
++}
++
++gboolean
++LibPinyinFullPinyinEditor::moveCursorLeftByWord (void)
++{
++    if (G_UNLIKELY (m_cursor == 0))
++        return FALSE;
++
++    guint cursor;
++
++    if (G_UNLIKELY (m_cursor > m_pinyin_len)) {
++        cursor = m_pinyin_len;
++    } else {
++        guint pinyin_cursor = getPinyinCursor ();
++        cursor = m_pinyins[pinyin_cursor].begin;
++        /* cursor at the begin of one pinyin */
++        g_return_val_if_fail (pinyin_cursor > 0, FALSE);
++        if ( cursor == m_cursor)
++            cursor = m_pinyins[pinyin_cursor - 1].begin;        
++    }
++
++    m_cursor = cursor;
++    update ();
++    return TRUE;
++}
++
++gboolean
++LibPinyinFullPinyinEditor::moveCursorRightByWord (void)
++{
++    if (G_UNLIKELY (m_cursor == m_text.length ()))
++        return FALSE;
++
++    guint cursor;
++
++    if (G_UNLIKELY (m_cursor > m_pinyin_len)) {
++        cursor = m_text.length ();
++    } else {
++        guint pinyin_cursor = getPinyinCursor ();
++        PinyinSegment py = m_pinyins[pinyin_cursor];
++        cursor = py.begin + py.len;
++    }
++
++    m_cursor = cursor;
++    update ();
++    return TRUE;
++}
++
++gboolean
++LibPinyinFullPinyinEditor::moveCursorToBegin (void)
++{
++    if (G_UNLIKELY (m_cursor == 0))
++        return TRUE;
++
++    m_cursor = 0;
++    update ();
++    return TRUE;
++}
++
++gboolean
++LibPinyinFullPinyinEditor::moveCursorToEnd (void)
++{
++    if (G_UNLIKELY (m_cursor == m_text.length ()))
++        return FALSE;
++
++    m_cursor = m_text.length ();
++    update ();
++    return TRUE;
+ }
+ 
+ gboolean
+-- 
+1.7.6.4
+
+
+From b9dce30dd8b368769f7843594ba3210a097bd6cc Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Wed, 21 Sep 2011 10:34:46 +0800
+Subject: [PATCH 27/71] use m_pinyin_poses in full pinyin editor
+
+---
+ src/PYPFullPinyinEditor.cc |   32 ++++++++++++++++++++++----------
+ 1 files changed, 22 insertions(+), 10 deletions(-)
+
+diff --git a/src/PYPFullPinyinEditor.cc b/src/PYPFullPinyinEditor.cc
+index 7e764c7..0a05c5a 100644
+--- a/src/PYPFullPinyinEditor.cc
++++ b/src/PYPFullPinyinEditor.cc
+@@ -95,11 +95,16 @@ LibPinyinFullPinyinEditor::removeWordBefore (void)
+         cursor = m_pinyin_len;
+     } else {
+         guint pinyin_cursor = getPinyinCursor ();
+-        cursor = m_pinyins[pinyin_cursor].begin;
++        PinyinKeyPos *pos = &g_array_index
++            (m_instance->m_pinyin_poses, PinyinKeyPos, pinyin_cursor);
++        cursor = pos->m_pos;
+         /* cursor at the begin of one pinyin */
+         g_return_val_if_fail (pinyin_cursor > 0, FALSE);
+-        if ( cursor == m_cursor)
+-            cursor = m_pinyins[pinyin_cursor - 1].begin;
++        if ( cursor == m_cursor) {
++            pos = &g_array_index
++                (m_instance->m_pinyin_poses, PinyinKeyPos, pinyin_cursor - 1);
++            cursor = pos->m_pos;
++        }
+     }
+ 
+     m_text.erase (cursor, m_cursor - cursor);
+@@ -121,8 +126,9 @@ LibPinyinFullPinyinEditor::removeWordAfter (void)
+         cursor = m_text.length ();
+     } else {
+         guint pinyin_cursor = getPinyinCursor ();
+-        PinyinSegment py = m_pinyins[pinyin_cursor];
+-        cursor = py.begin + py.len;
++        PinyinKeyPos *pos = &g_array_index
++            (m_instance->m_pinyin_poses, PinyinKeyPos, pinyin_cursor);
++        cursor = pos->m_pos + pos->m_len;
+     }
+ 
+     m_text.erase (m_cursor, cursor - m_cursor);
+@@ -165,11 +171,16 @@ LibPinyinFullPinyinEditor::moveCursorLeftByWord (void)
+         cursor = m_pinyin_len;
+     } else {
+         guint pinyin_cursor = getPinyinCursor ();
+-        cursor = m_pinyins[pinyin_cursor].begin;
++        PinyinKeyPos *pos = &g_array_index
++            (m_instance->m_pinyin_poses, PinyinKeyPos, pinyin_cursor);
++        cursor = pos->m_pos;
+         /* cursor at the begin of one pinyin */
+         g_return_val_if_fail (pinyin_cursor > 0, FALSE);
+-        if ( cursor == m_cursor)
+-            cursor = m_pinyins[pinyin_cursor - 1].begin;        
++        if ( cursor == m_cursor) {
++            pos = &g_array_index
++                (m_instance->m_pinyin_poses, PinyinKeyPos, pinyin_cursor - 1);
++            cursor = pos->m_pos;
++        }
+     }
+ 
+     m_cursor = cursor;
+@@ -189,8 +200,9 @@ LibPinyinFullPinyinEditor::moveCursorRightByWord (void)
+         cursor = m_text.length ();
+     } else {
+         guint pinyin_cursor = getPinyinCursor ();
+-        PinyinSegment py = m_pinyins[pinyin_cursor];
+-        cursor = py.begin + py.len;
++        PinyinKeyPos *pos = &g_array_index
++            (m_instance->m_pinyin_poses, PinyinKeyPos, pinyin_cursor);
++        cursor = pos->m_pos + pos->m_len;
+     }
+ 
+     m_cursor = cursor;
+-- 
+1.7.6.4
+
+
+From 9b3f8d14380de93c3b697a55cfd1df6dd8316eb3 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Wed, 21 Sep 2011 11:25:58 +0800
+Subject: [PATCH 28/71] use pinyin pos
+
+---
+ src/PYPPhoneticEditor.cc |   14 ++++++++------
+ src/PYPPinyinEditor.cc   |    8 ++++----
+ 2 files changed, 12 insertions(+), 10 deletions(-)
+
+diff --git a/src/PYPPhoneticEditor.cc b/src/PYPPhoneticEditor.cc
+index a26ce85..217e545 100644
+--- a/src/PYPPhoneticEditor.cc
++++ b/src/PYPPhoneticEditor.cc
+@@ -299,13 +299,15 @@ guint
+ LibPinyinPhoneticEditor::getPinyinCursor ()
+ {
+     /* Translate cursor position to pinyin position. */
+-    guint pinyin_cursor = m_pinyins.size ();
+-    PinyinArray::const_iterator iter = m_pinyins.begin ();
+-    for ( ; iter != m_pinyins.end (); ++iter) {
+-        guint end = iter->begin + iter->len;
+-        if ( iter->begin <= m_cursor && m_cursor < end )
+-            pinyin_cursor = iter - m_pinyins.begin ();
++    PinyinKeyPosVector & pinyin_poses = m_instance->m_pinyin_poses;
++    guint pinyin_cursor = pinyin_poses->len;
++    for (size_t i = 0; i < pinyin_poses->len; ++i) {
++        PinyinKeyPos *pos = &g_array_index
++            (pinyin_poses, PinyinKeyPos, i);
++        if (pos->get_pos () <= m_cursor && m_cursor < pos->get_end_pos ())
++            pinyin_cursor = i;
+     }
++
+     g_assert (pinyin_cursor >= 0);
+     return pinyin_cursor;
+ }
+diff --git a/src/PYPPinyinEditor.cc b/src/PYPPinyinEditor.cc
+index a435b82..68617a3 100644
+--- a/src/PYPPinyinEditor.cc
++++ b/src/PYPPinyinEditor.cc
+@@ -272,12 +272,12 @@ LibPinyinPinyinEditor::updateAuxiliaryText ()
+ 
+     /* Note: cursor handling is defered to full/double pinyin editors. */
+     guint pinyin_cursor = getPinyinCursor ();
+-    for (guint i = 0; i < m_pinyins.size (); ++i) {
++    PinyinKeyVector & pinyin_keys = m_instance->m_pinyin_keys;
++    for (guint i = 0; i < pinyin_keys->len; ++i) {
+         if (G_LIKELY (i))
+             m_buffer << ' ';
+-        const Pinyin *pinyin = m_pinyins[i];
+-        m_buffer << pinyin->sheng
+-                 << pinyin->yun;
++        PinyinKey * key = &g_array_index (pinyin_keys, PinyinKey, i);
++        m_buffer << key->get_key_string ();
+     }
+ 
+     /* append rest text */
+-- 
+1.7.6.4
+
+
+From 31e29393f3d7069c7dbbbda11d0cb354838a0e2c Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Wed, 21 Sep 2011 11:39:17 +0800
+Subject: [PATCH 29/71] re-factor full pinyin editor
+
+---
+ src/PYPFullPinyinEditor.cc |   83 +++++++++++++++++++------------------------
+ src/PYPFullPinyinEditor.h  |    3 ++
+ 2 files changed, 40 insertions(+), 46 deletions(-)
+
+diff --git a/src/PYPFullPinyinEditor.cc b/src/PYPFullPinyinEditor.cc
+index 0a05c5a..904064a 100644
+--- a/src/PYPFullPinyinEditor.cc
++++ b/src/PYPFullPinyinEditor.cc
+@@ -83,43 +83,35 @@ LibPinyinFullPinyinEditor::removeCharAfter (void)
+     return TRUE;
+ }
+ 
+-gboolean
+-LibPinyinFullPinyinEditor::removeWordBefore (void)
++guint
++LibPinyinFullPinyinEditor::getCursorLeftByWord (void)
+ {
+-    if (G_UNLIKELY (m_cursor == 0))
+-        return FALSE;
+-
+     guint cursor;
+ 
+     if (G_UNLIKELY (m_cursor > m_pinyin_len)) {
+         cursor = m_pinyin_len;
+     } else {
++        PinyinKeyPosVector & pinyin_poses = m_instance->m_pinyin_poses;
+         guint pinyin_cursor = getPinyinCursor ();
+         PinyinKeyPos *pos = &g_array_index
+-            (m_instance->m_pinyin_poses, PinyinKeyPos, pinyin_cursor);
++            (pinyin_poses, PinyinKeyPos, pinyin_cursor);
+         cursor = pos->m_pos;
++
+         /* cursor at the begin of one pinyin */
+-        g_return_val_if_fail (pinyin_cursor > 0, FALSE);
++        g_return_val_if_fail (pinyin_cursor > 0, 0);
+         if ( cursor == m_cursor) {
+             pos = &g_array_index
+-                (m_instance->m_pinyin_poses, PinyinKeyPos, pinyin_cursor - 1);
++                (pinyin_poses, PinyinKeyPos, pinyin_cursor - 1);
+             cursor = pos->m_pos;
+         }
+     }
+ 
+-    m_text.erase (cursor, m_cursor - cursor);
+-    m_cursor = cursor;
+-    updatePinyin ();
+-    update ();
+-    return TRUE;
++    return cursor;
+ }
+ 
+-gboolean
+-LibPinyinFullPinyinEditor::removeWordAfter (void)
++guint
++LibPinyinFullPinyinEditor::getCursorRightByWord (void)
+ {
+-    if (G_UNLIKELY (m_cursor == m_text.length ()))
+-        return FALSE;
+-
+     guint cursor;
+ 
+     if (G_UNLIKELY (m_cursor > m_pinyin_len)) {
+@@ -128,9 +120,33 @@ LibPinyinFullPinyinEditor::removeWordAfter (void)
+         guint pinyin_cursor = getPinyinCursor ();
+         PinyinKeyPos *pos = &g_array_index
+             (m_instance->m_pinyin_poses, PinyinKeyPos, pinyin_cursor);
+-        cursor = pos->m_pos + pos->m_len;
++        cursor = pos->get_end_pos ();
+     }
+ 
++    return cursor;
++}
++
++gboolean
++LibPinyinFullPinyinEditor::removeWordBefore (void)
++{
++    if (G_UNLIKELY (m_cursor == 0))
++        return FALSE;
++
++    guint cursor = getCursorLeftByWord ();
++    m_text.erase (cursor, m_cursor - cursor);
++    m_cursor = cursor;
++    updatePinyin ();
++    update ();
++    return TRUE;
++}
++
++gboolean
++LibPinyinFullPinyinEditor::removeWordAfter (void)
++{
++    if (G_UNLIKELY (m_cursor == m_text.length ()))
++        return FALSE;
++
++    guint cursor = getCursorRightByWord ();
+     m_text.erase (m_cursor, cursor - m_cursor);
+     updatePinyin ();
+     update ();
+@@ -165,23 +181,7 @@ LibPinyinFullPinyinEditor::moveCursorLeftByWord (void)
+     if (G_UNLIKELY (m_cursor == 0))
+         return FALSE;
+ 
+-    guint cursor;
+-
+-    if (G_UNLIKELY (m_cursor > m_pinyin_len)) {
+-        cursor = m_pinyin_len;
+-    } else {
+-        guint pinyin_cursor = getPinyinCursor ();
+-        PinyinKeyPos *pos = &g_array_index
+-            (m_instance->m_pinyin_poses, PinyinKeyPos, pinyin_cursor);
+-        cursor = pos->m_pos;
+-        /* cursor at the begin of one pinyin */
+-        g_return_val_if_fail (pinyin_cursor > 0, FALSE);
+-        if ( cursor == m_cursor) {
+-            pos = &g_array_index
+-                (m_instance->m_pinyin_poses, PinyinKeyPos, pinyin_cursor - 1);
+-            cursor = pos->m_pos;
+-        }
+-    }
++    guint cursor = getCursorLeftByWord ();
+ 
+     m_cursor = cursor;
+     update ();
+@@ -194,16 +194,7 @@ LibPinyinFullPinyinEditor::moveCursorRightByWord (void)
+     if (G_UNLIKELY (m_cursor == m_text.length ()))
+         return FALSE;
+ 
+-    guint cursor;
+-
+-    if (G_UNLIKELY (m_cursor > m_pinyin_len)) {
+-        cursor = m_text.length ();
+-    } else {
+-        guint pinyin_cursor = getPinyinCursor ();
+-        PinyinKeyPos *pos = &g_array_index
+-            (m_instance->m_pinyin_poses, PinyinKeyPos, pinyin_cursor);
+-        cursor = pos->m_pos + pos->m_len;
+-    }
++    guint cursor = getCursorRightByWord ();
+ 
+     m_cursor = cursor;
+     update ();
+diff --git a/src/PYPFullPinyinEditor.h b/src/PYPFullPinyinEditor.h
+index afb52d5..11e53cb 100644
+--- a/src/PYPFullPinyinEditor.h
++++ b/src/PYPFullPinyinEditor.h
+@@ -54,6 +54,9 @@ protected:
+     /* TODO: to be implemented. */
+     void updatePinyin (void);
+ 
++    guint getCursorLeftByWord (void);
++    guint getCursorRightByWord (void);
++
+ };
+ 
+ };
+-- 
+1.7.6.4
+
+
+From f612432ccf5bd9d3fc9617bf52f1f99e2b7b5c0a Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Wed, 21 Sep 2011 12:22:55 +0800
+Subject: [PATCH 30/71] add update aux text func for full pinyin
+
+---
+ src/PYPFullPinyinEditor.cc |   37 +++++++++++++++++++++++++++++++++++++
+ src/PYPFullPinyinEditor.h  |    2 ++
+ src/PYPPinyinEditor.cc     |    4 ++--
+ src/PYPPinyinEditor.h      |    6 +++---
+ 4 files changed, 44 insertions(+), 5 deletions(-)
+
+diff --git a/src/PYPFullPinyinEditor.cc b/src/PYPFullPinyinEditor.cc
+index 904064a..af29f53 100644
+--- a/src/PYPFullPinyinEditor.cc
++++ b/src/PYPFullPinyinEditor.cc
+@@ -262,3 +262,40 @@ LibPinyinFullPinyinEditor::updatePinyin (void)
+ 
+     pinyin_guess_sentence(m_instance);
+ }
++
++void
++LibPinyinFullPinyinEditor::updateAuxiliaryText ()
++{
++    if (G_UNLIKELY (m_text.empty ())) {
++        hideAuxiliaryText ();
++        return;
++    }
++
++    m_buffer.clear ();
++
++    guint pinyin_cursor = getPinyinCursor ();
++    PinyinKeyVector & pinyin_keys = m_instance->m_pinyin_keys;
++    PinyinKeyPosVector & pinyin_poses = m_instance->m_pinyin_poses;
++    for (guint i = 0; i < pinyin_keys->len; ++i) {
++        PinyinKey *key = &g_array_index (pinyin_keys, PinyinKey, i);
++        PinyinKeyPos *pos = &g_array_index (pinyin_poses, PinyinKeyPos, i);
++        guint cursor = pos->get_pos ();
++
++        if (G_UNLIKELY (cursor == m_cursor)) { /* at word boundary. */
++            m_buffer << '|' << key->get_key_string ();
++        } else { /* in word */
++            /* raw text */
++            String raw = m_text.substr (cursor, pos->get_length ());
++            guint offset = m_cursor - cursor;
++            m_buffer << ' ' << raw.substr (0, offset)
++                     << '|' << raw.substr (offset);
++        }
++    }
++
++    /* append rest text */
++    const gchar * p = m_text.c_str() + m_pinyin_len;
++    m_buffer << p;
++
++    StaticText aux_text (m_buffer);
++    Editor::updateAuxiliaryText (aux_text, TRUE);
++}
+diff --git a/src/PYPFullPinyinEditor.h b/src/PYPFullPinyinEditor.h
+index 11e53cb..5624c54 100644
+--- a/src/PYPFullPinyinEditor.h
++++ b/src/PYPFullPinyinEditor.h
+@@ -49,6 +49,8 @@ public:
+     /* virtual functions */
+     virtual gboolean processKeyEvent (guint keyval, guint keycode, guint modifiers);
+     virtual void reset (void);
++    virtual void updateAuxiliaryText (void);
++
+ 
+ protected:
+     /* TODO: to be implemented. */
+diff --git a/src/PYPPinyinEditor.cc b/src/PYPPinyinEditor.cc
+index 68617a3..b2e5987 100644
+--- a/src/PYPPinyinEditor.cc
++++ b/src/PYPPinyinEditor.cc
+@@ -276,12 +276,12 @@ LibPinyinPinyinEditor::updateAuxiliaryText ()
+     for (guint i = 0; i < pinyin_keys->len; ++i) {
+         if (G_LIKELY (i))
+             m_buffer << ' ';
+-        PinyinKey * key = &g_array_index (pinyin_keys, PinyinKey, i);
++        PinyinKey *key = &g_array_index (pinyin_keys, PinyinKey, i);
+         m_buffer << key->get_key_string ();
+     }
+ 
+     /* append rest text */
+-    const gchar * p = m_text.c_str() + m_pinyin_len;
++    const gchar *p = m_text.c_str() + m_pinyin_len;
+     m_buffer << p;
+ 
+     StaticText aux_text (m_buffer);
+diff --git a/src/PYPPinyinEditor.h b/src/PYPPinyinEditor.h
+index fd2b2ce..41aafc6 100644
+--- a/src/PYPPinyinEditor.h
++++ b/src/PYPPinyinEditor.h
+@@ -43,9 +43,9 @@ protected:
+ 
+     void commit ();
+ 
+-    void updateAuxiliaryText (void);
+-    void updateLookupTable (void);
+-    void updatePreeditText (void);
++    virtual void updateAuxiliaryText (void);
++    virtual void updateLookupTable (void);
++    virtual void updatePreeditText (void);
+ 
+     virtual gboolean processKeyEvent (guint keyval, guint keycode, guint modifiers);
+ 
+-- 
+1.7.6.4
+
+
+From 62d47f889316ff95b764333bb10f9f0211e32558 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Wed, 21 Sep 2011 14:02:14 +0800
+Subject: [PATCH 31/71] begin to add double pinyin editor
+
+---
+ src/Makefile.am              |    1 +
+ src/PYPDoublePinyinEditor.cc |   40 ++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 41 insertions(+), 0 deletions(-)
+ create mode 100644 src/PYPDoublePinyinEditor.cc
+
+diff --git a/src/Makefile.am b/src/Makefile.am
+index aeaaf89..a15a0ef 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -68,6 +68,7 @@ ibus_engine_pinyin_c_sources = \
+ 	PYPPhoneticEditor.cc \
+ 	PYPPinyinEditor.cc \
+ 	PYPFullPinyinEditor.cc \
++	PYPDoublePinyinEditor.cc \
+ 	PYPBopomofoEditor.cc \
+ 	$(NULL)
+ ibus_engine_pinyin_h_sources = \
+diff --git a/src/PYPDoublePinyinEditor.cc b/src/PYPDoublePinyinEditor.cc
+new file mode 100644
+index 0000000..5eb2067
+--- /dev/null
++++ b/src/PYPDoublePinyinEditor.cc
+@@ -0,0 +1,40 @@
++/* vim:set et ts=4 sts=4:
++ *
++ * ibus-pinyin - The Chinese PinYin engine for IBus
++ *
++ * Copyright (c) 2011 Peng Wu <alexepico at gmail.com>
++ *
++ * 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 "PYPDoublePinyinEditor.h"
++
++using namespace PY;
++
++
++gboolean
++LibPinyinDoublePinyinEditor::processKeyEvent (guint keyval, guint keycode,
++                                              guint modifiers)
++{
++    /* handle ';' key */
++    if (G_UNLIKELY (keyval == IBUS_semicolon)) {
++        if (cmshm_filter (modifiers) == 0) {
++            if (insert (keyval))
++                return TRUE;
++        }
++    }
++
++    return LibPinyinPinyinEditor::processKeyEvent (keyval, keycode, modifiers);
++}
+-- 
+1.7.6.4
+
+
+From 1e16137bf37a2bc597740585e2809679bc5b7605 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Wed, 21 Sep 2011 14:18:36 +0800
+Subject: [PATCH 32/71] move cursor edit funcs to pinyin editor
+
+---
+ src/PYPDoublePinyinEditor.h |    2 +
+ src/PYPFullPinyinEditor.cc  |  168 ------------------------------------------
+ src/PYPFullPinyinEditor.h   |   17 +----
+ src/PYPPinyinEditor.cc      |  169 +++++++++++++++++++++++++++++++++++++++++++
+ src/PYPPinyinEditor.h       |   18 +++++
+ 5 files changed, 190 insertions(+), 184 deletions(-)
+
+diff --git a/src/PYPDoublePinyinEditor.h b/src/PYPDoublePinyinEditor.h
+index 35baa6f..f0cb548 100644
+--- a/src/PYPDoublePinyinEditor.h
++++ b/src/PYPDoublePinyinEditor.h
+@@ -50,6 +50,8 @@ public:
+ 
+ protected:
+     /* TODO: to be implemented. */
++    virtual void updatePinyin (void);
++
+ };
+ 
+ };
+diff --git a/src/PYPFullPinyinEditor.cc b/src/PYPFullPinyinEditor.cc
+index af29f53..9c1644e 100644
+--- a/src/PYPFullPinyinEditor.cc
++++ b/src/PYPFullPinyinEditor.cc
+@@ -54,174 +54,6 @@ LibPinyinFullPinyinEditor::insert (gint ch)
+     return TRUE;
+ }
+ 
+-gboolean
+-LibPinyinFullPinyinEditor::removeCharBefore (void)
+-{
+-    if (G_UNLIKELY (m_cursor == 0))
+-        return FALSE;
+-
+-    m_cursor --;
+-    m_text.erase (m_cursor, 1);
+-
+-    updatePinyin ();
+-    update ();
+-
+-    return TRUE;
+-}
+-
+-gboolean
+-LibPinyinFullPinyinEditor::removeCharAfter (void)
+-{
+-    if (G_UNLIKELY (m_cursor == m_text.length ()))
+-        return FALSE;
+-
+-    m_text.erase (m_cursor, 1);
+-
+-    updatePinyin ();
+-    update ();
+-
+-    return TRUE;
+-}
+-
+-guint
+-LibPinyinFullPinyinEditor::getCursorLeftByWord (void)
+-{
+-    guint cursor;
+-
+-    if (G_UNLIKELY (m_cursor > m_pinyin_len)) {
+-        cursor = m_pinyin_len;
+-    } else {
+-        PinyinKeyPosVector & pinyin_poses = m_instance->m_pinyin_poses;
+-        guint pinyin_cursor = getPinyinCursor ();
+-        PinyinKeyPos *pos = &g_array_index
+-            (pinyin_poses, PinyinKeyPos, pinyin_cursor);
+-        cursor = pos->m_pos;
+-
+-        /* cursor at the begin of one pinyin */
+-        g_return_val_if_fail (pinyin_cursor > 0, 0);
+-        if ( cursor == m_cursor) {
+-            pos = &g_array_index
+-                (pinyin_poses, PinyinKeyPos, pinyin_cursor - 1);
+-            cursor = pos->m_pos;
+-        }
+-    }
+-
+-    return cursor;
+-}
+-
+-guint
+-LibPinyinFullPinyinEditor::getCursorRightByWord (void)
+-{
+-    guint cursor;
+-
+-    if (G_UNLIKELY (m_cursor > m_pinyin_len)) {
+-        cursor = m_text.length ();
+-    } else {
+-        guint pinyin_cursor = getPinyinCursor ();
+-        PinyinKeyPos *pos = &g_array_index
+-            (m_instance->m_pinyin_poses, PinyinKeyPos, pinyin_cursor);
+-        cursor = pos->get_end_pos ();
+-    }
+-
+-    return cursor;
+-}
+-
+-gboolean
+-LibPinyinFullPinyinEditor::removeWordBefore (void)
+-{
+-    if (G_UNLIKELY (m_cursor == 0))
+-        return FALSE;
+-
+-    guint cursor = getCursorLeftByWord ();
+-    m_text.erase (cursor, m_cursor - cursor);
+-    m_cursor = cursor;
+-    updatePinyin ();
+-    update ();
+-    return TRUE;
+-}
+-
+-gboolean
+-LibPinyinFullPinyinEditor::removeWordAfter (void)
+-{
+-    if (G_UNLIKELY (m_cursor == m_text.length ()))
+-        return FALSE;
+-
+-    guint cursor = getCursorRightByWord ();
+-    m_text.erase (m_cursor, cursor - m_cursor);
+-    updatePinyin ();
+-    update ();
+-    return TRUE;
+-}
+-
+-gboolean
+-LibPinyinFullPinyinEditor::moveCursorLeft (void)
+-{
+-    if (G_UNLIKELY (m_cursor == 0))
+-        return FALSE;
+-
+-    m_cursor --;
+-    update ();
+-    return TRUE;
+-}
+-
+-gboolean
+-LibPinyinFullPinyinEditor::moveCursorRight (void)
+-{
+-    if (G_UNLIKELY (m_cursor == m_text.length ()))
+-        return FALSE;
+-
+-    m_cursor ++;
+-    update ();
+-    return TRUE;
+-}
+-
+-gboolean
+-LibPinyinFullPinyinEditor::moveCursorLeftByWord (void)
+-{
+-    if (G_UNLIKELY (m_cursor == 0))
+-        return FALSE;
+-
+-    guint cursor = getCursorLeftByWord ();
+-
+-    m_cursor = cursor;
+-    update ();
+-    return TRUE;
+-}
+-
+-gboolean
+-LibPinyinFullPinyinEditor::moveCursorRightByWord (void)
+-{
+-    if (G_UNLIKELY (m_cursor == m_text.length ()))
+-        return FALSE;
+-
+-    guint cursor = getCursorRightByWord ();
+-
+-    m_cursor = cursor;
+-    update ();
+-    return TRUE;
+-}
+-
+-gboolean
+-LibPinyinFullPinyinEditor::moveCursorToBegin (void)
+-{
+-    if (G_UNLIKELY (m_cursor == 0))
+-        return TRUE;
+-
+-    m_cursor = 0;
+-    update ();
+-    return TRUE;
+-}
+-
+-gboolean
+-LibPinyinFullPinyinEditor::moveCursorToEnd (void)
+-{
+-    if (G_UNLIKELY (m_cursor == m_text.length ()))
+-        return FALSE;
+-
+-    m_cursor = m_text.length ();
+-    update ();
+-    return TRUE;
+-}
+ 
+ gboolean
+ LibPinyinFullPinyinEditor::processKeyEvent (guint keyval,
+diff --git a/src/PYPFullPinyinEditor.h b/src/PYPFullPinyinEditor.h
+index 5624c54..6214f22 100644
+--- a/src/PYPFullPinyinEditor.h
++++ b/src/PYPFullPinyinEditor.h
+@@ -34,18 +34,6 @@ public:
+ public:
+     gboolean insert (gint ch);
+ 
+-    gboolean removeCharBefore (void);
+-    gboolean removeCharAfter (void);
+-    gboolean removeWordBefore (void);
+-    gboolean removeWordAfter (void);
+-
+-    gboolean moveCursorLeft (void);
+-    gboolean moveCursorRight (void);
+-    gboolean moveCursorLeftByWord (void);
+-    gboolean moveCursorRightByWord (void);
+-    gboolean moveCursorToBegin (void);
+-    gboolean moveCursorToEnd (void);
+-
+     /* virtual functions */
+     virtual gboolean processKeyEvent (guint keyval, guint keycode, guint modifiers);
+     virtual void reset (void);
+@@ -54,10 +42,7 @@ public:
+ 
+ protected:
+     /* TODO: to be implemented. */
+-    void updatePinyin (void);
+-
+-    guint getCursorLeftByWord (void);
+-    guint getCursorRightByWord (void);
++    virtual void updatePinyin (void);
+ 
+ };
+ 
+diff --git a/src/PYPPinyinEditor.cc b/src/PYPPinyinEditor.cc
+index b2e5987..08fc04e 100644
+--- a/src/PYPPinyinEditor.cc
++++ b/src/PYPPinyinEditor.cc
+@@ -295,3 +295,172 @@ LibPinyinPinyinEditor::updateLookupTable ()
+     m_lookup_table.setOrientation (m_config.orientation ());
+     LibPinyinPhoneticEditor::updateLookupTable ();
+ }
++
++gboolean
++LibPinyinPinyinEditor::removeCharBefore (void)
++{
++    if (G_UNLIKELY (m_cursor == 0))
++        return FALSE;
++
++    m_cursor --;
++    m_text.erase (m_cursor, 1);
++
++    updatePinyin ();
++    update ();
++
++    return TRUE;
++}
++
++gboolean
++LibPinyinPinyinEditor::removeCharAfter (void)
++{
++    if (G_UNLIKELY (m_cursor == m_text.length ()))
++        return FALSE;
++
++    m_text.erase (m_cursor, 1);
++
++    updatePinyin ();
++    update ();
++
++    return TRUE;
++}
++
++guint
++LibPinyinPinyinEditor::getCursorLeftByWord (void)
++{
++    guint cursor;
++
++    if (G_UNLIKELY (m_cursor > m_pinyin_len)) {
++        cursor = m_pinyin_len;
++    } else {
++        PinyinKeyPosVector & pinyin_poses = m_instance->m_pinyin_poses;
++        guint pinyin_cursor = getPinyinCursor ();
++        PinyinKeyPos *pos = &g_array_index
++            (pinyin_poses, PinyinKeyPos, pinyin_cursor);
++        cursor = pos->m_pos;
++
++        /* cursor at the begin of one pinyin */
++        g_return_val_if_fail (pinyin_cursor > 0, 0);
++        if ( cursor == m_cursor) {
++            pos = &g_array_index
++                (pinyin_poses, PinyinKeyPos, pinyin_cursor - 1);
++            cursor = pos->m_pos;
++        }
++    }
++
++    return cursor;
++}
++
++guint
++LibPinyinPinyinEditor::getCursorRightByWord (void)
++{
++    guint cursor;
++
++    if (G_UNLIKELY (m_cursor > m_pinyin_len)) {
++        cursor = m_text.length ();
++    } else {
++        guint pinyin_cursor = getPinyinCursor ();
++        PinyinKeyPos *pos = &g_array_index
++            (m_instance->m_pinyin_poses, PinyinKeyPos, pinyin_cursor);
++        cursor = pos->get_end_pos ();
++    }
++
++    return cursor;
++}
++
++gboolean
++LibPinyinPinyinEditor::removeWordBefore (void)
++{
++    if (G_UNLIKELY (m_cursor == 0))
++        return FALSE;
++
++    guint cursor = getCursorLeftByWord ();
++    m_text.erase (cursor, m_cursor - cursor);
++    m_cursor = cursor;
++    updatePinyin ();
++    update ();
++    return TRUE;
++}
++
++gboolean
++LibPinyinPinyinEditor::removeWordAfter (void)
++{
++    if (G_UNLIKELY (m_cursor == m_text.length ()))
++        return FALSE;
++
++    guint cursor = getCursorRightByWord ();
++    m_text.erase (m_cursor, cursor - m_cursor);
++    updatePinyin ();
++    update ();
++    return TRUE;
++}
++
++gboolean
++LibPinyinPinyinEditor::moveCursorLeft (void)
++{
++    if (G_UNLIKELY (m_cursor == 0))
++        return FALSE;
++
++    m_cursor --;
++    update ();
++    return TRUE;
++}
++
++gboolean
++LibPinyinPinyinEditor::moveCursorRight (void)
++{
++    if (G_UNLIKELY (m_cursor == m_text.length ()))
++        return FALSE;
++
++    m_cursor ++;
++    update ();
++    return TRUE;
++}
++
++gboolean
++LibPinyinPinyinEditor::moveCursorLeftByWord (void)
++{
++    if (G_UNLIKELY (m_cursor == 0))
++        return FALSE;
++
++    guint cursor = getCursorLeftByWord ();
++
++    m_cursor = cursor;
++    update ();
++    return TRUE;
++}
++
++gboolean
++LibPinyinPinyinEditor::moveCursorRightByWord (void)
++{
++    if (G_UNLIKELY (m_cursor == m_text.length ()))
++        return FALSE;
++
++    guint cursor = getCursorRightByWord ();
++
++    m_cursor = cursor;
++    update ();
++    return TRUE;
++}
++
++gboolean
++LibPinyinPinyinEditor::moveCursorToBegin (void)
++{
++    if (G_UNLIKELY (m_cursor == 0))
++        return TRUE;
++
++    m_cursor = 0;
++    update ();
++    return TRUE;
++}
++
++gboolean
++LibPinyinPinyinEditor::moveCursorToEnd (void)
++{
++    if (G_UNLIKELY (m_cursor == m_text.length ()))
++        return FALSE;
++
++    m_cursor = m_text.length ();
++    update ();
++    return TRUE;
++}
+diff --git a/src/PYPPinyinEditor.h b/src/PYPPinyinEditor.h
+index 41aafc6..974d2a5 100644
+--- a/src/PYPPinyinEditor.h
++++ b/src/PYPPinyinEditor.h
+@@ -35,6 +35,20 @@ class LibPinyinPinyinEditor : public LibPinyinPhoneticEditor {
+ public:
+     LibPinyinPinyinEditor (PinyinProperties & props, Config & config);
+ 
++public:
++    gboolean removeCharBefore (void);
++    gboolean removeCharAfter (void);
++    gboolean removeWordBefore (void);
++    gboolean removeWordAfter (void);
++
++    gboolean moveCursorLeft (void);
++    gboolean moveCursorRight (void);
++    gboolean moveCursorLeftByWord (void);
++    gboolean moveCursorRightByWord (void);
++    gboolean moveCursorToBegin (void);
++    gboolean moveCursorToEnd (void);
++
++
+ protected:
+     gboolean processPinyin (guint keyval, guint keycode, guint modifiers);
+     gboolean processNumber (guint keyval, guint keycode, guint modifiers);
+@@ -49,6 +63,10 @@ protected:
+ 
+     virtual gboolean processKeyEvent (guint keyval, guint keycode, guint modifiers);
+ 
++    virtual void updatePinyin (void) = 0;
++
++    guint getCursorLeftByWord (void);
++    guint getCursorRightByWord (void);
+ };
+ 
+ };
+-- 
+1.7.6.4
+
+
+From 17a5f2c269d903f892b59ab2a28e8476b5fa0035 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Wed, 21 Sep 2011 14:52:09 +0800
+Subject: [PATCH 33/71] add update pinyin
+
+---
+ src/PYPDoublePinyinEditor.cc |   16 ++++++++++++++++
+ src/PYPDoublePinyinEditor.h  |   12 ------------
+ src/PYPFullPinyinEditor.cc   |    8 +++++---
+ 3 files changed, 21 insertions(+), 15 deletions(-)
+
+diff --git a/src/PYPDoublePinyinEditor.cc b/src/PYPDoublePinyinEditor.cc
+index 5eb2067..501ec30 100644
+--- a/src/PYPDoublePinyinEditor.cc
++++ b/src/PYPDoublePinyinEditor.cc
+@@ -38,3 +38,19 @@ LibPinyinDoublePinyinEditor::processKeyEvent (guint keyval, guint keycode,
+ 
+     return LibPinyinPinyinEditor::processKeyEvent (keyval, keycode, modifiers);
+ }
++
++void
++LibPinyinDoublePinyinEditor::updatePinyin (void)
++{
++    if (G_UNLIKELY (m_text.empty ())) {
++        m_pinyins.clear ();
++        m_pinyin_len = 0;
++        /* TODO: check whether to replace "" with NULL. */
++        pinyin_parse_more_double_pinyins (m_instance, "");
++        return;
++    }
++
++    m_pinyin_len =
++        pinyin_parse_more_double_pinyins (m_instance, m_text.c_str ());
++    pinyin_guess_sentence (m_instance);
++}
+diff --git a/src/PYPDoublePinyinEditor.h b/src/PYPDoublePinyinEditor.h
+index f0cb548..d756fbd 100644
+--- a/src/PYPDoublePinyinEditor.h
++++ b/src/PYPDoublePinyinEditor.h
+@@ -32,18 +32,6 @@ public:
+ 
+     gboolean insert (gint ch);
+ 
+-    gboolean removeCharBefore (void);
+-    gboolean removeCharAfter (void);
+-    gboolean removeWordBefore (void);
+-    gboolean removeWordAfter (void);
+-
+-    gboolean moveCursorLeft (void);
+-    gboolean moveCursorRight (void);
+-    gboolean moveCursorLeftByWord (void);
+-    gboolean moveCursorRightByWord (void);
+-    gboolean moveCursorToBegin (void);
+-    gboolean moveCursorToEnd (void);
+-
+     /* override virtual functions */
+     gboolean processKeyEvent (guint keyval, guint keycode, guint modifiers);
+     void reset (void);
+diff --git a/src/PYPFullPinyinEditor.cc b/src/PYPFullPinyinEditor.cc
+index 9c1644e..05de60d 100644
+--- a/src/PYPFullPinyinEditor.cc
++++ b/src/PYPFullPinyinEditor.cc
+@@ -69,6 +69,8 @@ LibPinyinFullPinyinEditor::updatePinyin (void)
+     if (G_UNLIKELY (m_text.empty ())) {
+         m_pinyins.clear ();
+         m_pinyin_len = 0;
++        /* TODO: check whether to replace "" with NULL. */
++        pinyin_parse_more_full_pinyins (m_instance, "");
+         return;
+     }
+ 
+@@ -88,11 +90,11 @@ LibPinyinFullPinyinEditor::updatePinyin (void)
+         PinyinSegment py = *iter;
+         pinyin_parse_full_pinyin (m_instance, py.pinyin->text, &key);
+         pos.set_pos (py.begin); pos.set_length (py.len);
+-        g_array_append_val(m_instance->m_pinyin_keys, key);
+-        g_array_append_val(m_instance->m_pinyin_poses, pos);
++        g_array_append_val (m_instance->m_pinyin_keys, key);
++        g_array_append_val (m_instance->m_pinyin_poses, pos);
+     }
+ 
+-    pinyin_guess_sentence(m_instance);
++    pinyin_guess_sentence (m_instance);
+ }
+ 
+ void
+-- 
+1.7.6.4
+
+
+From 15e5c137425de55f79c0c51d9ede5c9482e5f745 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Thu, 22 Sep 2011 14:24:09 +0800
+Subject: [PATCH 34/71] write double pinyin editor
+
+---
+ src/PYPDoublePinyinEditor.cc |   93 ++++++++++++++++++++++++++++++++++++++++++
+ src/PYPDoublePinyinEditor.h  |    1 +
+ src/PYPFullPinyinEditor.cc   |    2 +-
+ src/PYPPinyinEditor.cc       |    2 +-
+ 4 files changed, 96 insertions(+), 2 deletions(-)
+
+diff --git a/src/PYPDoublePinyinEditor.cc b/src/PYPDoublePinyinEditor.cc
+index 501ec30..0e1e3d3 100644
+--- a/src/PYPDoublePinyinEditor.cc
++++ b/src/PYPDoublePinyinEditor.cc
+@@ -20,9 +20,64 @@
+  */
+ 
+ #include "PYPDoublePinyinEditor.h"
++#include "PYConfig.h"
++
++#define DEFINE_DOUBLE_PINYIN_TABLES
++#include "PYDoublePinyinTable.h"
+ 
+ using namespace PY;
+ 
++/*
++ * c in 'a' ... 'z' => id = c - 'a'
++ * c == ';'         => id = 26
++ * else             => id = -1
++ */
++#define ID(c) \
++    ((c >= IBUS_a && c <= IBUS_z) ? c - IBUS_a : (c == IBUS_semicolon ? 26 : -1))
++
++#define ID_TO_SHENG(id) \
++    (double_pinyin_map[m_config.doublePinyinSchema ()].sheng[id])
++#define ID_TO_YUNS(id) \
++    (double_pinyin_map[m_config.doublePinyinSchema ()].yun[id])
++
++#define IS_ALPHA(c) \
++        ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
++
++
++LibPinyinDoublePinyinEditor::LibPinyinDoublePinyinEditor
++( PinyinProperties & props, Config & config)
++    : LibPinyinPinyinEditor (props, config)
++{
++}
++
++gboolean
++LibPinyinDoublePinyinEditor::insert (gint ch)
++{
++    /* is full */
++    if (G_UNLIKELY (m_text.length () >= MAX_PINYIN_LEN))
++        return TRUE;
++
++    gint id = ID (ch);
++    if (id == -1) {
++        /* it is not available ch */
++        return FALSE;
++    }
++
++    if (G_UNLIKELY (m_text.empty () && ID_TO_SHENG (id) == PINYIN_ID_VOID)) {
++        return FALSE;
++    }
++
++    m_text.insert (m_cursor++, ch);
++    updatePinyin ();
++    update ();
++
++    return TRUE;
++}
++
++void LibPinyinDoublePinyinEditor::reset (void)
++{
++    LibPinyinPinyinEditor::reset ();
++}
+ 
+ gboolean
+ LibPinyinDoublePinyinEditor::processKeyEvent (guint keyval, guint keycode,
+@@ -54,3 +109,41 @@ LibPinyinDoublePinyinEditor::updatePinyin (void)
+         pinyin_parse_more_double_pinyins (m_instance, m_text.c_str ());
+     pinyin_guess_sentence (m_instance);
+ }
++
++
++void
++LibPinyinDoublePinyinEditor::updateAuxiliaryText (void)
++{
++    if (G_UNLIKELY (m_text.empty ())) {
++        hideAuxiliaryText ();
++        return;
++    }
++
++    m_buffer.clear ();
++
++    // guint pinyin_cursor = getPinyinCursor ();
++    PinyinKeyVector & pinyin_keys = m_instance->m_pinyin_keys;
++    PinyinKeyPosVector & pinyin_poses = m_instance->m_pinyin_poses;
++    for (guint i = 0; i < pinyin_keys->len; ++i) {
++        PinyinKey *key = &g_array_index (pinyin_keys, PinyinKey, i);
++        PinyinKeyPos *pos = &g_array_index (pinyin_poses, PinyinKeyPos, i);
++        guint cursor = pos->get_pos ();
++
++        if (G_UNLIKELY (cursor == m_cursor)) { /* at word boundary. */
++            m_buffer << '|' << key->get_key_string ();
++        } else { /* in word */
++            /* raw text */
++            String raw = m_text.substr (cursor, pos->get_length ());
++            guint offset = m_cursor - cursor;
++            m_buffer << ' ' << raw.substr (0, offset)
++                     << '|' << raw.substr (offset);
++        }
++    }
++
++    /* append rest text */
++    const gchar * p = m_text.c_str() + m_pinyin_len;
++    m_buffer << p;
++
++    StaticText aux_text (m_buffer);
++    Editor::updateAuxiliaryText (aux_text, TRUE);
++}
+diff --git a/src/PYPDoublePinyinEditor.h b/src/PYPDoublePinyinEditor.h
+index d756fbd..b06e144 100644
+--- a/src/PYPDoublePinyinEditor.h
++++ b/src/PYPDoublePinyinEditor.h
+@@ -38,6 +38,7 @@ public:
+ 
+ protected:
+     /* TODO: to be implemented. */
++    virtual void updateAuxiliaryText (void);
+     virtual void updatePinyin (void);
+ 
+ };
+diff --git a/src/PYPFullPinyinEditor.cc b/src/PYPFullPinyinEditor.cc
+index 05de60d..80f8a46 100644
+--- a/src/PYPFullPinyinEditor.cc
++++ b/src/PYPFullPinyinEditor.cc
+@@ -107,7 +107,7 @@ LibPinyinFullPinyinEditor::updateAuxiliaryText ()
+ 
+     m_buffer.clear ();
+ 
+-    guint pinyin_cursor = getPinyinCursor ();
++    // guint pinyin_cursor = getPinyinCursor ();
+     PinyinKeyVector & pinyin_keys = m_instance->m_pinyin_keys;
+     PinyinKeyPosVector & pinyin_poses = m_instance->m_pinyin_poses;
+     for (guint i = 0; i < pinyin_keys->len; ++i) {
+diff --git a/src/PYPPinyinEditor.cc b/src/PYPPinyinEditor.cc
+index 08fc04e..8108002 100644
+--- a/src/PYPPinyinEditor.cc
++++ b/src/PYPPinyinEditor.cc
+@@ -271,7 +271,7 @@ LibPinyinPinyinEditor::updateAuxiliaryText ()
+     m_buffer.clear ();
+ 
+     /* Note: cursor handling is defered to full/double pinyin editors. */
+-    guint pinyin_cursor = getPinyinCursor ();
++    // guint pinyin_cursor = getPinyinCursor ();
+     PinyinKeyVector & pinyin_keys = m_instance->m_pinyin_keys;
+     for (guint i = 0; i < pinyin_keys->len; ++i) {
+         if (G_LIKELY (i))
+-- 
+1.7.6.4
+
+
+From dc1008b9450edadac06e5927f4bfc53914339619 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Thu, 22 Sep 2011 14:35:40 +0800
+Subject: [PATCH 35/71] begin to write bopomofo editor
+
+---
+ src/PYPBopomofoEditor.cc |  119 ----------------------------------------------
+ src/PYPBopomofoEditor.h  |   20 ++------
+ src/PYPPhoneticEditor.h  |    2 +
+ src/PYPPinyinEditor.h    |    2 +-
+ 4 files changed, 8 insertions(+), 135 deletions(-)
+
+diff --git a/src/PYPBopomofoEditor.cc b/src/PYPBopomofoEditor.cc
+index 35c9ed2..9efd8f1 100644
+--- a/src/PYPBopomofoEditor.cc
++++ b/src/PYPBopomofoEditor.cc
+@@ -72,125 +72,6 @@ LibPinyinBopomofoEditor::insert (gint ch)
+     return TRUE;
+ }
+ 
+-gboolean
+-LibPinyinBopomofoEditor::removeCharBefore (void)
+-{
+-    if (G_UNLIKELY (m_cursor == 0))
+-        return FALSE;
+-
+-    m_cursor --;
+-    m_text.erase (m_cursor, 1);
+-    update();
+-
+-    return TRUE;
+-}
+-
+-gboolean
+-LibPinyinBopomofoEditor::removeCharAfter (void)
+-{
+-    if (G_UNLIKELY (m_cursor == m_text.length ()))
+-        return FALSE;
+-
+-    m_text.erase (m_cursor, 1);
+-    update ();
+-
+-    return TRUE;
+-}
+-
+-gboolean
+-LibPinyinBopomofoEditor::removeWordBefore (void)
+-{
+-    if (G_UNLIKELY (m_cursor == 0))
+-        return FALSE;
+-
+-    /* TODO: to be implemented. */
+-    g_assert(FALSE);
+-
+-    return TRUE;
+-}
+-
+-gboolean
+-LibPinyinBopomofoEditor::removeWordAfter (void)
+-{
+-    if (G_UNLIKELY (m_cursor == m_text.length ()))
+-        return FALSE;
+-
+-    /* TODO: remove one word instead of the sentence. */
+-    g_assert(FALSE);
+-
+-    return TRUE;
+-}
+-
+-gboolean
+-LibPinyinBopomofoEditor::moveCursorLeft (void)
+-{
+-    if (G_UNLIKELY (m_cursor == 0))
+-        return FALSE;
+-
+-    m_cursor --;
+-    update ();
+-
+-    return TRUE;
+-}
+-
+-gboolean
+-LibPinyinBopomofoEditor::moveCursorRight (void)
+-{
+-    if (G_UNLIKELY (m_cursor == m_text.length ()))
+-        return FALSE;
+-
+-    m_cursor ++;
+-    update ();
+-
+-    return TRUE;
+-}
+-
+-gboolean
+-LibPinyinBopomofoEditor::moveCursorLeftByWord (void)
+-{
+-    if (G_UNLIKELY (m_cursor == 0))
+-        return FALSE;
+-
+-    /* TODO: to be implemented. */
+-    g_assert(FALSE);
+-
+-    return TRUE;
+-}
+-
+-gboolean
+-LibPinyinBopomofoEditor::moveCursorRightByWord (void)
+-{
+-    if (G_UNLIKELY (m_cursor == m_text.length ()))
+-        return FALSE;
+-
+-    /* TODO: to be implemented. */
+-    g_assert(FALSE);
+-
+-    return TRUE;
+-}
+-
+-gboolean
+-LibPinyinBopomofoEditor::moveCursorToBegin (void)
+-{
+-    if (G_UNLIKELY (m_cursor == 0))
+-        return FALSE;
+-
+-    m_cursor = 0;
+-    update();
+-
+-    return TRUE;
+-}
+-
+-gboolean
+-LibPinyinBopomofoEditor::moveCursorToEnd (void)
+-{
+-    if (G_UNLIKELY (m_cursor == m_text.length ()))
+-        return FALSE;
+-
+-    m_cursor = m_text.length ();
+-    update();
+-    return TRUE;
+-}
+ 
+ gboolean
+ LibPinyinBopomofoEditor::processGuideKey (guint keyval, guint keycode,
+diff --git a/src/PYPBopomofoEditor.h b/src/PYPBopomofoEditor.h
+index f78375f..9b6b4b6 100644
+--- a/src/PYPBopomofoEditor.h
++++ b/src/PYPBopomofoEditor.h
+@@ -46,31 +46,21 @@ protected:
+     gboolean processBopomofo (guint keyval, guint keycode, guint modifiers);
+     gboolean processKeyEvent (guint keyval, guint keycode, guint modifiers);
+ 
++
++    virtual void updateAuxiliaryText ();
++    virtual void updatePinyin (void);
++
+ #if 0
+-    void updateAuxiliaryText ();
+     void updateLookupTable ();
+     void updatePreeditText ();
++#endif
+ 
+-    void update ();
+     void commit ();
+-#endif
+     void reset ();
+ 
+     gboolean insert (gint ch);
+     gint keyvalToBopomofo (gint ch);
+ 
+-    gboolean removeCharBefore (void);
+-    gboolean removeCharAfter (void);
+-    gboolean removeWordBefore (void);
+-    gboolean removeWordAfter (void);
+-
+-    gboolean moveCursorLeft (void);
+-    gboolean moveCursorRight (void);
+-    gboolean moveCursorLeftByWord (void);
+-    gboolean moveCursorRightByWord (void);
+-    gboolean moveCursorToBegin (void);
+-    gboolean moveCursorToEnd (void);
+-
+ };
+ 
+ };
+diff --git a/src/PYPPhoneticEditor.h b/src/PYPPhoneticEditor.h
+index 428f17b..56a8ee4 100644
+--- a/src/PYPPhoneticEditor.h
++++ b/src/PYPPhoneticEditor.h
+@@ -74,6 +74,8 @@ protected:
+     virtual void commit (void) = 0;
+     virtual void updateAuxiliaryText (void) = 0;
+     virtual void updatePreeditText (void) = 0;
++    virtual void updatePinyin (void) = 0;
++
+ 
+     /* varibles */
+     PinyinArray                 m_pinyins;
+diff --git a/src/PYPPinyinEditor.h b/src/PYPPinyinEditor.h
+index 974d2a5..00b49ce 100644
+--- a/src/PYPPinyinEditor.h
++++ b/src/PYPPinyinEditor.h
+@@ -63,7 +63,7 @@ protected:
+ 
+     virtual gboolean processKeyEvent (guint keyval, guint keycode, guint modifiers);
+ 
+-    virtual void updatePinyin (void) = 0;
++    virtual void updatePinyin (void);
+ 
+     guint getCursorLeftByWord (void);
+     guint getCursorRightByWord (void);
+-- 
+1.7.6.4
+
+
+From 4fa55bf0d8333d1bb21c64572d017e05a22f4d48 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Thu, 22 Sep 2011 15:00:11 +0800
+Subject: [PATCH 36/71] write bopomofo editor in progress
+
+---
+ src/PYPBopomofoEditor.cc |   68 ++++++++++++++++++++++++++++++++++++++++++++++
+ src/PYPPinyinEditor.h    |    2 +-
+ 2 files changed, 69 insertions(+), 1 deletions(-)
+
+diff --git a/src/PYPBopomofoEditor.cc b/src/PYPBopomofoEditor.cc
+index 9efd8f1..3a2a70e 100644
+--- a/src/PYPBopomofoEditor.cc
++++ b/src/PYPBopomofoEditor.cc
+@@ -226,6 +226,22 @@ LibPinyinBopomofoEditor::processKeyEvent (guint keyval, guint keycode,
+     return FALSE;
+ }
+ 
++void
++LibPinyinBopomofoEditor::updatePinyin (void)
++{
++    if (G_UNLIKELY (m_text.empty ())) {
++        m_pinyins.clear ();
++        m_pinyin_len = 0;
++        /* TODO: check whether to replace "" with NULL. */
++        pinyin_parse_more_chewings (m_instance, "");
++        return;
++    }
++
++    m_pinyin_len =
++        pinyin_parse_more_chewings (m_instance, m_text.c_str ());
++    pinyin_guess_sentence (m_instance);
++}
++
+ gint
+ LibPinyinBopomofoEditor::keyvalToBopomofo(gint ch)
+ {
+@@ -239,3 +255,55 @@ LibPinyinBopomofoEditor::keyvalToBopomofo(gint ch)
+ 
+     return BOPOMOFO_ZERO;
+ }
++
++void
++LibPinyinBopomofoEditor::commit ()
++{
++    g_assert (FALSE);
++}
++
++void
++LibPinyinBopomofoEditor::updateAuxiliaryText (void)
++{
++    if (G_UNLIKELY (m_text.empty ())) {
++        hideAuxiliaryText ();
++        return;
++    }
++
++    m_buffer.clear ();
++
++    // guint pinyin_cursor = getPinyinCursor ();
++    PinyinKeyVector & pinyin_keys = m_instance->m_pinyin_keys;
++    PinyinKeyPosVector & pinyin_poses = m_instance->m_pinyin_poses;
++    for (guint i = 0; i < pinyin_keys->len; ++i) {
++        PinyinKey *key = &g_array_index (pinyin_keys, PinyinKey, i);
++        PinyinKeyPos *pos = &g_array_index (pinyin_poses, PinyinKeyPos, i);
++        guint cursor = pos->get_pos ();
++
++        if (G_UNLIKELY (cursor == m_cursor)) { /* at word boundary. */
++            m_buffer << '|' << key->get_key_zhuyin_string ();
++        } else { /* in word */
++            /* raw text */
++            String raw = m_text.substr (cursor, pos->get_length ());
++            guint offset = m_cursor - cursor;
++            m_buffer << ' ';
++            String before = raw.substr (0, offset);
++            String after = raw.substr (offset);
++            String::const_iterator iter;
++            for ( iter = before.begin (); iter != before.end (); ++iter) {
++                m_buffer << bopomofo_char[keyvalToBopomofo (*iter)];
++            }
++            m_buffer << '|';
++            for ( iter = after.begin (); iter != after.end (); ++iter) {
++                m_buffer << bopomofo_char[keyvalToBopomofo (*iter)];
++            }
++        }
++    }
++
++    /* append rest text */
++    const gchar * p = m_text.c_str() + m_pinyin_len;
++    m_buffer << p;
++
++    StaticText aux_text (m_buffer);
++    Editor::updateAuxiliaryText (aux_text, TRUE);
++}
+diff --git a/src/PYPPinyinEditor.h b/src/PYPPinyinEditor.h
+index 00b49ce..974d2a5 100644
+--- a/src/PYPPinyinEditor.h
++++ b/src/PYPPinyinEditor.h
+@@ -63,7 +63,7 @@ protected:
+ 
+     virtual gboolean processKeyEvent (guint keyval, guint keycode, guint modifiers);
+ 
+-    virtual void updatePinyin (void);
++    virtual void updatePinyin (void) = 0;
+ 
+     guint getCursorLeftByWord (void);
+     guint getCursorRightByWord (void);
+-- 
+1.7.6.4
+
+
+From cd133bc9853f92d5c8ab72fd74a9a4d0670390fe Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Thu, 22 Sep 2011 15:18:37 +0800
+Subject: [PATCH 37/71] write bopomofo editor
+
+---
+ src/PYPBopomofoEditor.cc |   35 ++++++++++++++++++++++++++++++++++-
+ src/PYPPinyinEditor.cc   |   10 ++++++----
+ 2 files changed, 40 insertions(+), 5 deletions(-)
+
+diff --git a/src/PYPBopomofoEditor.cc b/src/PYPBopomofoEditor.cc
+index 3a2a70e..023634b 100644
+--- a/src/PYPBopomofoEditor.cc
++++ b/src/PYPBopomofoEditor.cc
+@@ -22,6 +22,8 @@
+ #include "PYConfig.h"
+ #include "PYPinyinProperties.h"
+ #include "PYSimpTradConverter.h"
++#include "PYHalfFullConverter.h"
++
+ 
+ namespace PY {
+ #include "PYBopomofoKeyboard.h"
+@@ -259,7 +261,38 @@ LibPinyinBopomofoEditor::keyvalToBopomofo(gint ch)
+ void
+ LibPinyinBopomofoEditor::commit ()
+ {
+-    g_assert (FALSE);
++    if (G_UNLIKELY (m_text.empty ()))
++        return;
++
++    m_buffer.clear ();
++
++    /* sentence candidate */
++    char *tmp = NULL;
++    pinyin_get_sentence(m_instance, &tmp);
++    if (m_props.modeSimp ()) {
++        m_buffer << tmp;
++    } else {
++        SimpTradConverter::simpToTrad (tmp, m_buffer);
++    }
++    g_free (tmp);
++
++    /* text after pinyin */
++    const gchar *p = m_text.c_str() + m_pinyin_len;
++    while (*p != '\0') {
++        if (keyvalToBopomofo (*p)) {
++            m_buffer << keyvalToBopomofo (*p);
++        } else {
++            if (G_UNLIKELY (m_props.modeFull ())) {
++                m_buffer.appendUnichar (HalfFullConverter::toFull (*p++));
++            } else {
++                m_buffer << p;
++            }
++        }
++    }
++
++    pinyin_train(m_instance);
++    LibPinyinPhoneticEditor::commit ((const gchar *)m_buffer);
++    reset();
+ }
+ 
+ void
+diff --git a/src/PYPPinyinEditor.cc b/src/PYPPinyinEditor.cc
+index 8108002..5599416 100644
+--- a/src/PYPPinyinEditor.cc
++++ b/src/PYPPinyinEditor.cc
+@@ -200,8 +200,7 @@ LibPinyinPinyinEditor::processKeyEvent (guint keyval, guint keycode,
+ void
+ LibPinyinPinyinEditor::commit ()
+ {
+-
+-    if (G_UNLIKELY (m_buffer.empty ()))
++    if (G_UNLIKELY (m_text.empty ()))
+         return;
+ 
+     m_buffer.clear ();
+@@ -209,9 +208,12 @@ LibPinyinPinyinEditor::commit ()
+     /* sentence candidate */
+     char *tmp = NULL;
+     pinyin_get_sentence(m_instance, &tmp);
+-    m_buffer << tmp;
++    if (m_props.modeSimp ()) {
++        m_buffer << tmp;
++    } else {
++        SimpTradConverter::simpToTrad (tmp, m_buffer);
++    }
+     g_free (tmp);
+-    tmp = NULL;
+ 
+     /* text after pinyin */
+     const gchar *p = m_text.c_str() + m_pinyin_len;
+-- 
+1.7.6.4
+
+
+From 57d303dd2b725c56abea46490609e0cd3d1f2938 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Thu, 22 Sep 2011 15:31:06 +0800
+Subject: [PATCH 38/71] remove m_pinyins
+
+---
+ src/PYPBopomofoEditor.cc     |    1 -
+ src/PYPDoublePinyinEditor.cc |    1 -
+ src/PYPFullPinyinEditor.cc   |    9 +++++----
+ src/PYPPhoneticEditor.cc     |    2 --
+ src/PYPPhoneticEditor.h      |    2 ++
+ 5 files changed, 7 insertions(+), 8 deletions(-)
+
+diff --git a/src/PYPBopomofoEditor.cc b/src/PYPBopomofoEditor.cc
+index 023634b..0c7e46f 100644
+--- a/src/PYPBopomofoEditor.cc
++++ b/src/PYPBopomofoEditor.cc
+@@ -232,7 +232,6 @@ void
+ LibPinyinBopomofoEditor::updatePinyin (void)
+ {
+     if (G_UNLIKELY (m_text.empty ())) {
+-        m_pinyins.clear ();
+         m_pinyin_len = 0;
+         /* TODO: check whether to replace "" with NULL. */
+         pinyin_parse_more_chewings (m_instance, "");
+diff --git a/src/PYPDoublePinyinEditor.cc b/src/PYPDoublePinyinEditor.cc
+index 0e1e3d3..d37a480 100644
+--- a/src/PYPDoublePinyinEditor.cc
++++ b/src/PYPDoublePinyinEditor.cc
+@@ -98,7 +98,6 @@ void
+ LibPinyinDoublePinyinEditor::updatePinyin (void)
+ {
+     if (G_UNLIKELY (m_text.empty ())) {
+-        m_pinyins.clear ();
+         m_pinyin_len = 0;
+         /* TODO: check whether to replace "" with NULL. */
+         pinyin_parse_more_double_pinyins (m_instance, "");
+diff --git a/src/PYPFullPinyinEditor.cc b/src/PYPFullPinyinEditor.cc
+index 80f8a46..064ae40 100644
+--- a/src/PYPFullPinyinEditor.cc
++++ b/src/PYPFullPinyinEditor.cc
+@@ -67,17 +67,18 @@ void
+ LibPinyinFullPinyinEditor::updatePinyin (void)
+ {
+     if (G_UNLIKELY (m_text.empty ())) {
+-        m_pinyins.clear ();
+         m_pinyin_len = 0;
+         /* TODO: check whether to replace "" with NULL. */
+         pinyin_parse_more_full_pinyins (m_instance, "");
+         return;
+     }
+ 
++    PinyinArray pinyins (MAX_PINYIN_LEN);
++
+     m_pinyin_len = PinyinParser::parse (m_text,               // text
+                                         m_text.length (),     // text length
+                                         m_config.option (),   // option
+-                                        m_pinyins,            // result
++                                        pinyins,              // result
+                                         MAX_PHRASE_LEN);      // max result length
+ 
+     /* propagate to libpinyin */
+@@ -85,8 +86,8 @@ LibPinyinFullPinyinEditor::updatePinyin (void)
+     g_array_set_size (m_instance->m_pinyin_poses, 0);
+ 
+     PinyinKey key; PinyinKeyPos pos;
+-    PinyinArray::const_iterator iter = m_pinyins.begin ();
+-    for ( ; iter != m_pinyins.end (); ++iter ) {
++    PinyinArray::const_iterator iter = pinyins.begin ();
++    for ( ; iter != pinyins.end (); ++iter ) {
+         PinyinSegment py = *iter;
+         pinyin_parse_full_pinyin (m_instance, py.pinyin->text, &key);
+         pos.set_pos (py.begin); pos.set_length (py.len);
+diff --git a/src/PYPPhoneticEditor.cc b/src/PYPPhoneticEditor.cc
+index 217e545..60e2da9 100644
+--- a/src/PYPPhoneticEditor.cc
++++ b/src/PYPPhoneticEditor.cc
+@@ -29,7 +29,6 @@ using namespace PY;
+ LibPinyinPhoneticEditor::LibPinyinPhoneticEditor (PinyinProperties &props,
+                                                   Config &config):
+     Editor (props, config),
+-    m_pinyins (MAX_PHRASE_LEN),
+     m_pinyin_len (0),
+     m_lookup_table (m_config.pageSize ())
+ {
+@@ -273,7 +272,6 @@ LibPinyinPhoneticEditor::candidateClicked (guint index, guint button, guint stat
+ void
+ LibPinyinPhoneticEditor::reset (void)
+ {
+-    m_pinyins.clear ();
+     m_pinyin_len = 0;
+     m_lookup_table.clear ();
+ 
+diff --git a/src/PYPPhoneticEditor.h b/src/PYPPhoneticEditor.h
+index 56a8ee4..9d522bf 100644
+--- a/src/PYPPhoneticEditor.h
++++ b/src/PYPPhoneticEditor.h
+@@ -78,7 +78,9 @@ protected:
+ 
+ 
+     /* varibles */
++#if 0
+     PinyinArray                 m_pinyins;
++#endif
+     guint                       m_pinyin_len;
+     LookupTable                 m_lookup_table;
+     String                      m_buffer;
+-- 
+1.7.6.4
+
+
+From f37f4807b0408d4269ad6a57e8a29049c18cabb1 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Thu, 22 Sep 2011 15:49:29 +0800
+Subject: [PATCH 39/71] fixes Makefile.am
+
+---
+ src/Makefile.am          |    2 ++
+ src/PYPBopomofoEditor.cc |    1 +
+ 2 files changed, 3 insertions(+), 0 deletions(-)
+
+diff --git a/src/Makefile.am b/src/Makefile.am
+index a15a0ef..4a83521 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -115,6 +115,8 @@ ibus_engine_pinyin_h_sources = \
+ 	PYLibPinyin.h \
+ 	PYPPhoneticEditor.h \
+ 	PYPPinyinEditor.h \
++	PYPFullPinyinEditor.h \
++	PYPDoublePinyinEditor.h \
+ 	PYPBopomofoEditor.h \
+ 	$(NULL)
+ 
+diff --git a/src/PYPBopomofoEditor.cc b/src/PYPBopomofoEditor.cc
+index 0c7e46f..db4f9b4 100644
+--- a/src/PYPBopomofoEditor.cc
++++ b/src/PYPBopomofoEditor.cc
+@@ -69,6 +69,7 @@ LibPinyinBopomofoEditor::insert (gint ch)
+         return TRUE;
+ 
+     m_text.insert (m_cursor++, ch);
++    updatePinyin ();
+     update ();
+ 
+     return TRUE;
+-- 
+1.7.6.4
+
+
+From 4adb383aeaeb0053f161283888609ea3078e2bdb Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Fri, 23 Sep 2011 14:44:10 +0800
+Subject: [PATCH 40/71] add set chewing options
+
+---
+ src/PYLibPinyin.cc |   29 ++++++++++++++++++++++++++++-
+ src/PYLibPinyin.h  |    3 ++-
+ 2 files changed, 30 insertions(+), 2 deletions(-)
+
+diff --git a/src/PYLibPinyin.cc b/src/PYLibPinyin.cc
+index 36eaba3..ceada04 100644
+--- a/src/PYLibPinyin.cc
++++ b/src/PYLibPinyin.cc
+@@ -43,7 +43,7 @@ LibPinyinBackEnd::~LibPinyinBackEnd(){
+ /* Here are the fuzzy pinyin options conversion table. */
+ static const struct {
+     guint ibus_pinyin_option;
+-    PinyinAmbiguity libpinyin_option;    
++    PinyinAmbiguity libpinyin_option;
+ } fuzzy_options [] = {
+     /* fuzzy pinyin */
+     { PINYIN_FUZZY_C_CH,        PINYIN_AmbCiChi        },
+@@ -68,6 +68,7 @@ static const struct {
+     { PINYIN_FUZZY_ING_IN,      PINYIN_AmbIngIn        }
+ };
+ 
++
+ gboolean
+ LibPinyinBackEnd::setPinyinOptions (Config * config)
+ {
+@@ -88,3 +89,29 @@ LibPinyinBackEnd::setPinyinOptions (Config * config)
+ 
+     return TRUE;
+ }
++
++/* Here are the chewing keyboard scheme mapping table. */
++static const struct {
++    guint bopomofo_keyboard;
++    PinyinZhuYinScheme chewing_keyboard;
++} chewing_options [] = {
++    {0, ZHUYIN_STANDARD},
++    {1, ZHUYIN_GIN_YIEH},
++    {2, ZHUYIN_ET26},
++    {3, ZHUYIN_IBM}
++};
++
++
++gboolean
++LibPinyinBackEnd::setChewingOptions (Config *config)
++{
++    const guint map = config->bopomofoKeyboardMapping ();
++    for (guint i = 0; i < G_N_ELEMENTS (chewing_options); i++) {
++        if (map == chewing_options[i].bopomofo_keyboard){
++            /* TODO: set chewing scheme. */
++            PinyinZhuYinScheme scheme = chewing_options[i].chewing_keyboard;
++            g_assert (FALSE);
++        }            
++    }
++    return TRUE;
++}
+diff --git a/src/PYLibPinyin.h b/src/PYLibPinyin.h
+index 83aa1fc..538930c 100644
+--- a/src/PYLibPinyin.h
++++ b/src/PYLibPinyin.h
+@@ -35,7 +35,8 @@ public:
+     LibPinyinBackEnd();
+     ~LibPinyinBackEnd();
+ 
+-    gboolean setPinyinOptions(Config *config);
++    gboolean setPinyinOptions (Config *config);
++    gboolean setChewingOptions (Config *config);
+ 
+     /* use static initializer in C++. */
+     static LibPinyinBackEnd & instance (void) { return *m_instance; }
+-- 
+1.7.6.4
+
+
+From 67ddca2bedeb5716ba8f2ec049d67f65db562a80 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Mon, 26 Sep 2011 15:33:00 +0800
+Subject: [PATCH 41/71] add libpinyin pinyin/chewing scheme options
+
+---
+ src/PYLibPinyin.cc |   45 ++++++++++++++++++++++++++++++++++++++-------
+ src/PYLibPinyin.h  |    7 ++++++-
+ 2 files changed, 44 insertions(+), 8 deletions(-)
+
+diff --git a/src/PYLibPinyin.cc b/src/PYLibPinyin.cc
+index ceada04..8e3d7af 100644
+--- a/src/PYLibPinyin.cc
++++ b/src/PYLibPinyin.cc
+@@ -70,7 +70,7 @@ static const struct {
+ 
+ 
+ gboolean
+-LibPinyinBackEnd::setPinyinOptions (Config * config)
++LibPinyinBackEnd::setFuzzyOptions (Config *config, pinyin_context_t *context)
+ {
+     guint option = config->option ();
+     PinyinCustomSettings custom;
+@@ -85,14 +85,43 @@ LibPinyinBackEnd::setPinyinOptions (Config * config)
+                 (fuzzy_options[i].libpinyin_option, true);
+     }
+ 
+-    pinyin_set_options(m_pinyin_context, &custom);
++    pinyin_set_options(context, &custom);
+ 
+     return TRUE;
+ }
+ 
++/* Here are the double pinyin keyboard scheme mapping table. */
++static const struct{
++    gint double_pinyin_keyboard;
++    PinyinShuangPinScheme shuang_pin_keyboard;
++} shuang_pin_options [] = {
++    {0, SHUANG_PIN_MS},
++    {1, SHUANG_PIN_ZRM},
++    {2, SHUANG_PIN_ABC},
++    {3, SHUANG_PIN_ZIGUANG},
++    {4, SHUANG_PIN_PYJJ},
++    {5, SHUANG_PIN_XHE}
++};
++
++gboolean
++LibPinyinBackEnd::setPinyinOptions (Config *config)
++{
++    const gint map = config->doublePinyinSchema ();
++    for (guint i = 0; i < G_N_ELEMENTS (shuang_pin_options); i++) {
++        if (map == shuang_pin_options[i].double_pinyin_keyboard) {
++            /* TODO: set double pinyin scheme. */
++            PinyinShuangPinScheme scheme = shuang_pin_options[i].shuang_pin_keyboard;
++            pinyin_set_double_pinyin_scheme (m_pinyin_context, scheme);
++        }
++    }
++
++    setFuzzyOptions (config, m_pinyin_context);
++    return TRUE;
++}
++
+ /* Here are the chewing keyboard scheme mapping table. */
+ static const struct {
+-    guint bopomofo_keyboard;
++    gint bopomofo_keyboard;
+     PinyinZhuYinScheme chewing_keyboard;
+ } chewing_options [] = {
+     {0, ZHUYIN_STANDARD},
+@@ -105,13 +134,15 @@ static const struct {
+ gboolean
+ LibPinyinBackEnd::setChewingOptions (Config *config)
+ {
+-    const guint map = config->bopomofoKeyboardMapping ();
++    const gint map = config->bopomofoKeyboardMapping ();
+     for (guint i = 0; i < G_N_ELEMENTS (chewing_options); i++) {
+-        if (map == chewing_options[i].bopomofo_keyboard){
++        if (map == chewing_options[i].bopomofo_keyboard) {
+             /* TODO: set chewing scheme. */
+             PinyinZhuYinScheme scheme = chewing_options[i].chewing_keyboard;
+-            g_assert (FALSE);
+-        }            
++            pinyin_set_chewing_scheme (m_chewing_context, scheme);
++        }
+     }
++
++    setFuzzyOptions (config, m_chewing_context);
+     return TRUE;
+ }
+diff --git a/src/PYLibPinyin.h b/src/PYLibPinyin.h
+index 538930c..3d40b1d 100644
+--- a/src/PYLibPinyin.h
++++ b/src/PYLibPinyin.h
+@@ -41,8 +41,13 @@ public:
+     /* use static initializer in C++. */
+     static LibPinyinBackEnd & instance (void) { return *m_instance; }
+ 
++protected:
++    gboolean setFuzzyOptions (Config *config, pinyin_context_t *context);
++
+ private:
+-    pinyin_context_t *m_pinyin_context; /* libpinyin context */
++    /* libpinyin context */
++    pinyin_context_t *m_pinyin_context;
++    pinyin_context_t *m_chewing_context;
+ 
+ private:
+     static std::unique_ptr<LibPinyinBackEnd> m_instance;
+-- 
+1.7.6.4
+
+
+From 97cd3846b283bb7554604f692f027a5259ab4380 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Wed, 28 Sep 2011 15:08:11 +0800
+Subject: [PATCH 42/71] add PYPPinyinEngine.h
+
+---
+ src/Makefile.am       |    1 +
+ src/PYPPinyinEngine.h |   80 +++++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 81 insertions(+), 0 deletions(-)
+ create mode 100644 src/PYPPinyinEngine.h
+
+diff --git a/src/Makefile.am b/src/Makefile.am
+index 4a83521..be20605 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -118,6 +118,7 @@ ibus_engine_pinyin_h_sources = \
+ 	PYPFullPinyinEditor.h \
+ 	PYPDoublePinyinEditor.h \
+ 	PYPBopomofoEditor.h \
++	PYPPinyinEngine.h \
+ 	$(NULL)
+ 
+ if IBUS_BUILD_LUA_EXTENSION
+diff --git a/src/PYPPinyinEngine.h b/src/PYPPinyinEngine.h
+new file mode 100644
+index 0000000..d8040c1
+--- /dev/null
++++ b/src/PYPPinyinEngine.h
+@@ -0,0 +1,80 @@
++/* vim:set et ts=4 sts=4:
++ *
++ * ibus-pinyin - The Chinese PinYin engine for IBus
++ *
++ * Copyright (c) 2008-2010 Peng Huang <shawn.p.huang at gmail.com>
++ * Copyright (c) 2011 Peng Wu <alexepico at gmail.com>
++ *
++ * 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.
++ */
++#ifndef __PY_LIB_PINYIN_PINYIN_ENGINE_H_
++#define __PY_LIB_PINYIN_PINYIN_ENGINE_H_
++
++#include "PYEngine.h"
++#include "PYPinyinProperties.h"
++
++namespace PY {
++class LibPinyinPinyinEngine : public Engine {
++public:
++    LibPinyinPinyinEngine (IBusEngine *engine);
++    ~LibPinyinPinyinEngine (void);
++
++    //virtual functions
++    gboolean processKeyEvent (guint keyval, guint keycode, guint modifiers);
++    void focusIn (void);
++    void focusOut (void);
++    void reset (void);
++    void enable (void);
++    void disable (void);
++    void pageUp (void);
++    void pageDown (void);
++    void cursorUp (void);
++    void cursorDown (void);
++    gboolean propertyActivate (const gchar *prop_name, guint prop_state);
++    void candidateClicked (guint index, guint button, guint state);
++
++private:
++    gboolean processPunct (guint keyval, guint keycode, guint modifiers);
++
++    void showSetupDialog (void);
++    void connectEditorSignals (EditorPtr editor);
++
++    void commitText (Text & text);
++
++private:
++    PinyinProperties m_props;
++
++    guint m_prev_pressed_key;
++
++    enum {
++        MODE_INIT = 0,          // init mode
++        MODE_PUNCT,             // punct mode
++        MODE_RAW,               // raw mode
++        MODE_ENGLISH,           // press v into English input mode
++    #if 0
++        MODE_STROKE,            // press u into stroke input mode
++    #endif
++        MODE_EXTENSION,         // press i into extension input mode
++        MODE_LAST,
++    } m_input_mode;
++
++    EditorPtr m_editors[MODE_LAST];
++    EditorPtr m_fallback_editor;
++
++};
++
++};
++
++#endif
+-- 
+1.7.6.4
+
+
+From 269e8a835a6ac38a1c4b099f9a62bde9375e9a21 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Wed, 28 Sep 2011 17:09:11 +0800
+Subject: [PATCH 43/71] add libpinyin pinyin engine
+
+---
+ src/Makefile.am        |    1 +
+ src/PYPPinyinEngine.cc |  325 ++++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 326 insertions(+), 0 deletions(-)
+ create mode 100644 src/PYPPinyinEngine.cc
+
+diff --git a/src/Makefile.am b/src/Makefile.am
+index be20605..fc73a9b 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -70,6 +70,7 @@ ibus_engine_pinyin_c_sources = \
+ 	PYPFullPinyinEditor.cc \
+ 	PYPDoublePinyinEditor.cc \
+ 	PYPBopomofoEditor.cc \
++	PYPPinyinEngine.cc \
+ 	$(NULL)
+ ibus_engine_pinyin_h_sources = \
+ 	PYBopomofo.h \
+diff --git a/src/PYPPinyinEngine.cc b/src/PYPPinyinEngine.cc
+new file mode 100644
+index 0000000..2877702
+--- /dev/null
++++ b/src/PYPPinyinEngine.cc
+@@ -0,0 +1,325 @@
++/* vim:set et ts=4 sts=4:
++ *
++ * ibus-pinyin - The Chinese PinYin engine for IBus
++ *
++ * Copyright (c) 2008-2010 Peng Huang <shawn.p.huang at gmail.com>
++ * Copyright (c) 2011 Peng Wu <alexepico at gmail.com>
++ *
++ * 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 "PYPPinyinEngine.h"
++#include <string>
++#include "PYConfig.h"
++#include "PYPunctEditor.h"
++#include "PYRawEditor.h"
++#ifdef IBUS_BUILD_LUA_EXTENSION
++#include "PYExtEditor.h"
++#endif
++#ifdef IBUS_BUILD_ENGLISH_INPUT_MODE
++#include "PYEnglishEditor.h"
++#endif
++#include "PYPFullPinyinEditor.h"
++#include "PYPDoublePinyinEditor.h"
++#include "PYFallbackEditor.h"
++
++using namespace PY;
++
++/* constructor */
++LibPinyinPinyinEngine::LibPinyinPinyinEngine (IBusEngine *engine)
++    : Engine (engine),
++      m_props (PinyinConfig::instance ()),
++      m_prev_pressed_key (IBUS_VoidSymbol),
++      m_input_mode (MODE_INIT),
++      m_fallback_editor (new FallbackEditor (m_props, PinyinConfig::instance ()))
++{
++    gint i;
++
++    if (PinyinConfig::instance ().doublePinyin ())
++        m_editors[MODE_INIT].reset
++            (new LibPinyinDoublePinyinEditor (m_props, PinyinConfig::instance ()));
++    else
++        m_editors[MODE_INIT].reset
++            (new LibPinyinFullPinyinEditor (m_props, PinyinConfig::instance ()));
++
++    m_editors[MODE_PUNCT].reset
++        (new PunctEditor (m_props, PinyinConfig::instance ()));
++    m_editors[MODE_RAW].reset
++        (new RawEditor (m_props, PinyinConfig::instance ()));
++
++#ifdef IBUS_BUILD_LUA_EXTENSION
++    m_editors[MODE_EXTENSION].reset (new ExtEditor (m_props, PinyinConfig::instance ()));
++#else
++    m_editors[MODE_EXTENSION].reset (new Editor (m_props, PinyinConfig::instance ()));
++#endif
++#ifdef IBUS_BUILD_ENGLISH_INPUT_MODE
++    m_editors[MODE_ENGLISH].reset (new EnglishEditor (m_props, PinyinConfig::instance ()));
++#else
++    m_editors[MODE_ENGLISH].reset (new Editor (m_props, PinyinConfig::instance ()));
++#endif
++
++    m_props.signalUpdateProperty ().connect
++        (std::bind (&LibPinyinPinyinEngine::updateProperty, this, _1));
++
++    for (i = MODE_INIT; i < MODE_LAST; i++) {
++        connectEditorSignals (m_editors[i]);
++    }
++
++    connectEditorSignals (m_fallback_editor);
++}
++
++/* destructor */
++LibPinyinPinyinEngine::~LibPinyinPinyinEngine (void)
++{
++}
++
++gboolean
++LibPinyinPinyinEngine::processKeyEvent (guint keyval, guint keycode, guint modifiers)
++{
++    gboolean retval = FALSE;
++
++    /* check Shift + Release hotkey,
++     * and then ignore other Release key event */
++    if (modifiers & IBUS_RELEASE_MASK) {
++        /* press and release keyval are same,
++         * and no other key event between the press and release key event */
++        if (m_prev_pressed_key == keyval){
++            if (keyval == IBUS_Shift_L || keyval == IBUS_Shift_R) {
++                if (!m_editors[MODE_INIT]->text ().empty ())
++                    m_editors[MODE_INIT]->reset ();
++                m_props.toggleModeChinese ();
++                return TRUE;
++            }
++        }
++
++        if (m_input_mode == MODE_INIT &&
++            m_editors[MODE_INIT]->text ().empty ()) {
++            /* If it is in init mode, and  no any previous input text,
++             * we will let client applications to handle release key event */
++            return FALSE;
++        }
++        else {
++            return TRUE;
++        }
++    }
++
++    /* Toggle simp/trad Chinese Mode when hotkey Ctrl + Shift + F pressed */
++    if (keyval == IBUS_F && scmshm_test (modifiers, (IBUS_SHIFT_MASK | IBUS_CONTROL_MASK))) {
++        m_props.toggleModeSimp ();
++        m_prev_pressed_key = IBUS_F;
++        return TRUE;
++    }
++
++    if (m_props.modeChinese ()) {
++        if (m_input_mode == MODE_INIT &&
++            (cmshm_filter (modifiers) == 0)) {
++            const String & text = m_editors[MODE_INIT]->text ();
++            if (text.empty ()) {
++                switch (keyval) {
++                case IBUS_grave:
++                    m_input_mode = MODE_PUNCT;
++                    break;
++#ifdef IBUS_BUILD_LUA_EXTENSION
++                case IBUS_i:
++                    // do not enable lua extension when use double pinyin.
++                    if (PinyinConfig::instance ().doublePinyin ())
++                        break;
++                    m_input_mode = MODE_EXTENSION;
++                    break;
++#endif
++#ifdef IBUS_BUILD_ENGLISH_INPUT_MODE
++                case IBUS_v:
++                    // do not enable english mode when use double pinyin.
++                    if (PinyinConfig::instance ().doublePinyin ())
++                        break;
++                    m_input_mode = MODE_ENGLISH;
++                    break;
++#endif
++                }
++            } else {
++                if (m_prev_pressed_key != IBUS_period) {
++                    if ((keyval == IBUS_at || keyval == IBUS_colon)) {
++                        m_input_mode = MODE_RAW;
++                        m_editors[MODE_RAW]->setText (text, text.length ());
++                        m_editors[MODE_INIT]->reset ();
++                    }
++                }
++                else {
++                    if ((keyval >= IBUS_a && keyval <= IBUS_z) ||
++                        (keyval >= IBUS_A && keyval <= IBUS_Z)) {
++                        String tmp = text;
++                        tmp += ".";
++                        m_input_mode = MODE_RAW;
++                        m_editors[MODE_RAW]->setText (tmp, tmp.length ());
++                        m_editors[MODE_INIT]->reset ();
++                    }
++                }
++            }
++        }
++        retval = m_editors[m_input_mode]->processKeyEvent (keyval, keycode, modifiers);
++        if (G_UNLIKELY (retval &&
++                        m_input_mode != MODE_INIT &&
++                        m_editors[m_input_mode]->text ().empty ()))
++            m_input_mode = MODE_INIT;
++    }
++
++    if (G_UNLIKELY (!retval))
++        retval = m_fallback_editor->processKeyEvent (keyval, keycode, modifiers);
++
++    /* store ignored key event by editors */
++    m_prev_pressed_key = retval ? IBUS_VoidSymbol : keyval;
++
++    return retval;
++}
++
++void
++LibPinyinPinyinEngine::focusIn (void)
++{
++    /* TODO: check memory leak here,
++     *       or switch full/double pinyin when pinyin config is changed.*/
++    if (PinyinConfig::instance ().doublePinyin ()) {
++        if (dynamic_cast <LibPinyinDoublePinyinEditor *> (m_editors[MODE_INIT].get ()) == NULL) {
++            m_editors[MODE_INIT].reset (new LibPinyinDoublePinyinEditor (m_props, PinyinConfig::instance ()));
++            connectEditorSignals (m_editors[MODE_INIT]);
++        }
++    }
++    else {
++        if (dynamic_cast <LibPinyinFullPinyinEditor *> (m_editors[MODE_INIT].get ()) == NULL) {
++            m_editors[MODE_INIT].reset (new LibPinyinFullPinyinEditor (m_props, PinyinConfig::instance ()));
++            connectEditorSignals (m_editors[MODE_INIT]);
++        }
++    }
++    registerProperties (m_props.properties ());
++}
++
++void
++LibPinyinPinyinEngine::focusOut (void)
++{
++    reset ();
++}
++
++void
++LibPinyinPinyinEngine::reset (void)
++{
++    m_prev_pressed_key = IBUS_VoidSymbol;
++    m_input_mode = MODE_INIT;
++    for (gint i = 0; i < MODE_LAST; i++) {
++        m_editors[i]->reset ();
++    }
++    m_fallback_editor->reset ();
++}
++
++void
++LibPinyinPinyinEngine::enable (void)
++{
++    m_props.reset ();
++}
++
++void
++LibPinyinPinyinEngine::disable (void)
++{
++}
++
++void
++LibPinyinPinyinEngine::pageUp (void)
++{
++    m_editors[m_input_mode]->pageUp ();
++}
++
++void
++LibPinyinPinyinEngine::pageDown (void)
++{
++    m_editors[m_input_mode]->pageDown ();
++}
++
++void
++LibPinyinPinyinEngine::cursorUp (void)
++{
++    m_editors[m_input_mode]->cursorUp ();
++}
++
++void
++LibPinyinPinyinEngine::cursorDown (void)
++{
++    m_editors[m_input_mode]->cursorDown ();
++}
++
++inline void
++LibPinyinPinyinEngine::showSetupDialog (void)
++{
++    /* TODO: to be implemented */
++    g_assert (FALSE);
++}
++
++gboolean
++LibPinyinPinyinEngine::propertyActivate (const char *prop_name, guint prop_state)
++{
++    const static String setup ("setup");
++    if (m_props.propertyActivate (prop_name, prop_state)) {
++        return TRUE;
++    }
++    else if (setup == prop_name) {
++        showSetupDialog ();
++        return TRUE;
++    }
++    return FALSE;
++}
++
++void
++LibPinyinPinyinEngine::candidateClicked (guint index, guint button, guint state)
++{
++    m_editors[m_input_mode]->candidateClicked (index, button, state);
++}
++
++void
++LibPinyinPinyinEngine::commitText (Text & text)
++{
++    Engine::commitText (text);
++    if (m_input_mode != MODE_INIT)
++        m_input_mode = MODE_INIT;
++    if (text.text ())
++        static_cast<FallbackEditor*> (m_fallback_editor.get ())->setPrevCommittedChar (*text.text ());
++    else
++        static_cast<FallbackEditor*> (m_fallback_editor.get ())->setPrevCommittedChar (0);
++}
++
++void
++LibPinyinPinyinEngine::connectEditorSignals (EditorPtr editor)
++{
++    editor->signalCommitText ().connect (
++        std::bind (&LibPinyinPinyinEngine::commitText, this, _1));
++
++    editor->signalUpdatePreeditText ().connect (
++        std::bind (&LibPinyinPinyinEngine::updatePreeditText, this, _1, _2, _3));
++    editor->signalShowPreeditText ().connect (
++        std::bind (&LibPinyinPinyinEngine::showPreeditText, this));
++    editor->signalHidePreeditText ().connect (
++        std::bind (&LibPinyinPinyinEngine::hidePreeditText, this));
++
++    editor->signalUpdateAuxiliaryText ().connect (
++        std::bind (&LibPinyinPinyinEngine::updateAuxiliaryText, this, _1, _2));
++    editor->signalShowAuxiliaryText ().connect (
++        std::bind (&LibPinyinPinyinEngine::showAuxiliaryText, this));
++    editor->signalHideAuxiliaryText ().connect (
++        std::bind (&LibPinyinPinyinEngine::hideAuxiliaryText, this));
++
++    editor->signalUpdateLookupTable ().connect (
++        std::bind (&LibPinyinPinyinEngine::updateLookupTable, this, _1, _2));
++    editor->signalUpdateLookupTableFast ().connect (
++        std::bind (&LibPinyinPinyinEngine::updateLookupTableFast, this, _1, _2));
++    editor->signalShowLookupTable ().connect (
++        std::bind (&LibPinyinPinyinEngine::showLookupTable, this));
++    editor->signalHideLookupTable ().connect (
++        std::bind (&LibPinyinPinyinEngine::hideLookupTable, this));
++}
+-- 
+1.7.6.4
+
+
+From a0b8bc5114056a844e59998766c886f26768cef8 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Wed, 28 Sep 2011 17:30:41 +0800
+Subject: [PATCH 44/71] write bopomofo editor
+
+---
+ src/PYPBopomofoEditor.cc |  131 ++++++++++++++++++++++++++++++++++++++++++++++
+ src/PYPBopomofoEditor.h  |   14 ++++--
+ src/PYPPhoneticEditor.cc |   71 +++++++++++++++++++++++++
+ src/PYPPhoneticEditor.h  |   12 ++--
+ 4 files changed, 218 insertions(+), 10 deletions(-)
+
+diff --git a/src/PYPBopomofoEditor.cc b/src/PYPBopomofoEditor.cc
+index db4f9b4..1945183 100644
+--- a/src/PYPBopomofoEditor.cc
++++ b/src/PYPBopomofoEditor.cc
+@@ -296,6 +296,38 @@ LibPinyinBopomofoEditor::commit ()
+ }
+ 
+ void
++LibPinyinBopomofoEditor::updatePreeditText ()
++{
++    /* preedit text = guessed sentence + un-parsed pinyin text */
++    if (G_UNLIKELY (m_text.empty ())) {
++        hidePreeditText ();
++        return;
++    }
++
++    m_buffer.clear ();
++    char *tmp = NULL;
++    pinyin_get_sentence(m_instance, &tmp);
++    if (m_props.modeSimp ()) {
++        m_buffer<<tmp;
++    } else {
++        SimpTradConverter::simpToTrad (tmp, m_buffer);
++    }
++    g_free (tmp);
++    tmp = NULL;
++
++    /* append rest text */
++    const gchar *p = m_text.c_str () + m_pinyin_len;
++    m_buffer << p;
++
++    StaticText preedit_text (m_buffer);
++    /* underline */
++    preedit_text.appendAttribute (IBUS_ATTR_TYPE_UNDERLINE, IBUS_ATTR_UNDERLINE_SINGLE, 0, -1);
++
++    guint pinyin_cursor = getPinyinCursor ();
++    Editor::updatePreeditText (preedit_text, pinyin_cursor, TRUE);
++}
++
++void
+ LibPinyinBopomofoEditor::updateAuxiliaryText (void)
+ {
+     if (G_UNLIKELY (m_text.empty ())) {
+@@ -340,3 +372,102 @@ LibPinyinBopomofoEditor::updateAuxiliaryText (void)
+     StaticText aux_text (m_buffer);
+     Editor::updateAuxiliaryText (aux_text, TRUE);
+ }
++
++/* move cursor functions */
++
++guint
++LibPinyinBopomofoEditor::getCursorLeftByWord (void)
++{
++    guint cursor;
++
++    if (G_UNLIKELY (m_cursor > m_pinyin_len)) {
++        cursor = m_pinyin_len;
++    } else {
++        PinyinKeyPosVector & pinyin_poses = m_instance->m_pinyin_poses;
++        guint pinyin_cursor = getPinyinCursor ();
++        PinyinKeyPos *pos = &g_array_index
++            (pinyin_poses, PinyinKeyPos, pinyin_cursor);
++        cursor = pos->m_pos;
++
++        /* cursor at the begin of one pinyin */
++        g_return_val_if_fail (pinyin_cursor > 0, 0);
++        if ( cursor == m_cursor) {
++            pos = &g_array_index
++                (pinyin_poses, PinyinKeyPos, pinyin_cursor - 1);
++            cursor = pos->m_pos;
++        }
++    }
++
++    return cursor;
++}
++
++guint
++LibPinyinBopomofoEditor::getCursorRightByWord (void)
++{
++    guint cursor;
++
++    if (G_UNLIKELY (m_cursor > m_pinyin_len)) {
++        cursor = m_text.length ();
++    } else {
++        guint pinyin_cursor = getPinyinCursor ();
++        PinyinKeyPos *pos = &g_array_index
++            (m_instance->m_pinyin_poses, PinyinKeyPos, pinyin_cursor);
++        cursor = pos->get_end_pos ();
++    }
++
++    return cursor;
++}
++
++gboolean
++LibPinyinBopomofoEditor::removeWordBefore (void)
++{
++    if (G_UNLIKELY (m_cursor == 0))
++        return FALSE;
++
++    guint cursor = getCursorLeftByWord ();
++    m_text.erase (cursor, m_cursor - cursor);
++    m_cursor = cursor;
++    updatePinyin ();
++    update ();
++    return TRUE;
++}
++
++gboolean
++LibPinyinBopomofoEditor::removeWordAfter (void)
++{
++    if (G_UNLIKELY (m_cursor == m_text.length ()))
++        return FALSE;
++
++    guint cursor = getCursorRightByWord ();
++    m_text.erase (m_cursor, cursor - m_cursor);
++    updatePinyin ();
++    update ();
++    return TRUE;
++}
++
++gboolean
++LibPinyinBopomofoEditor::moveCursorLeftByWord (void)
++{
++    if (G_UNLIKELY (m_cursor == 0))
++        return FALSE;
++
++    guint cursor = getCursorLeftByWord ();
++
++    m_cursor = cursor;
++    update ();
++    return TRUE;
++}
++
++gboolean
++LibPinyinBopomofoEditor::moveCursorRightByWord (void)
++{
++    if (G_UNLIKELY (m_cursor == m_text.length ()))
++        return FALSE;
++
++    guint cursor = getCursorRightByWord ();
++
++    m_cursor = cursor;
++    update ();
++    return TRUE;
++}
++
+diff --git a/src/PYPBopomofoEditor.h b/src/PYPBopomofoEditor.h
+index 9b6b4b6..cfdca2a 100644
+--- a/src/PYPBopomofoEditor.h
++++ b/src/PYPBopomofoEditor.h
+@@ -35,6 +35,13 @@ public:
+     LibPinyinBopomofoEditor (PinyinProperties & props, Config & config);
+     ~LibPinyinBopomofoEditor (void);
+ 
++public:
++    gboolean removeWordBefore (void);
++    gboolean removeWordAfter (void);
++
++    gboolean moveCursorLeftByWord (void);
++    gboolean moveCursorRightByWord (void);
++
+ protected:
+     String bopomofo;
+     gboolean m_select_mode;
+@@ -47,13 +54,12 @@ protected:
+     gboolean processKeyEvent (guint keyval, guint keycode, guint modifiers);
+ 
+ 
++    virtual void updatePreeditText ();
+     virtual void updateAuxiliaryText ();
+     virtual void updatePinyin (void);
+ 
+-#if 0
+-    void updateLookupTable ();
+-    void updatePreeditText ();
+-#endif
++    guint getCursorLeftByWord (void);
++    guint getCursorRightByWord (void);
+ 
+     void commit ();
+     void reset ();
+diff --git a/src/PYPPhoneticEditor.cc b/src/PYPPhoneticEditor.cc
+index 60e2da9..6fde250 100644
+--- a/src/PYPPhoneticEditor.cc
++++ b/src/PYPPhoneticEditor.cc
+@@ -334,4 +334,75 @@ LibPinyinPhoneticEditor::selectCandidateInPage (guint i)
+     return selectCandidate (i);
+ }
+ 
++gboolean
++LibPinyinPhoneticEditor::removeCharBefore (void)
++{
++    if (G_UNLIKELY (m_cursor == 0))
++        return FALSE;
++
++    m_cursor --;
++    m_text.erase (m_cursor, 1);
++
++    updatePinyin ();
++    update ();
++
++    return TRUE;
++}
++
++gboolean
++LibPinyinPhoneticEditor::removeCharAfter (void)
++{
++    if (G_UNLIKELY (m_cursor == m_text.length ()))
++        return FALSE;
++
++    m_text.erase (m_cursor, 1);
++
++    updatePinyin ();
++    update ();
++
++    return TRUE;
++}
++
++gboolean
++LibPinyinPhoneticEditor::moveCursorLeft (void)
++{
++    if (G_UNLIKELY (m_cursor == 0))
++        return FALSE;
++
++    m_cursor --;
++    update ();
++    return TRUE;
++}
++
++gboolean
++LibPinyinPhoneticEditor::moveCursorRight (void)
++{
++    if (G_UNLIKELY (m_cursor == m_text.length ()))
++        return FALSE;
++
++    m_cursor ++;
++    update ();
++    return TRUE;
++}
++
++gboolean
++LibPinyinPhoneticEditor::moveCursorToBegin (void)
++{
++    if (G_UNLIKELY (m_cursor == 0))
++        return TRUE;
++
++    m_cursor = 0;
++    update ();
++    return TRUE;
++}
+ 
++gboolean
++LibPinyinPhoneticEditor::moveCursorToEnd (void)
++{
++    if (G_UNLIKELY (m_cursor == m_text.length ()))
++        return FALSE;
++
++    m_cursor = m_text.length ();
++    update ();
++    return TRUE;
++}
+diff --git a/src/PYPPhoneticEditor.h b/src/PYPPhoneticEditor.h
+index 9d522bf..f2d7309 100644
+--- a/src/PYPPhoneticEditor.h
++++ b/src/PYPPhoneticEditor.h
+@@ -61,16 +61,16 @@ protected:
+ 
+     /* pure virtual functions */
+     virtual gboolean insert (gint ch) = 0;
+-    virtual gboolean removeCharBefore (void) = 0;
+-    virtual gboolean removeCharAfter (void) = 0;
++    virtual gboolean removeCharBefore (void);
++    virtual gboolean removeCharAfter (void);
+     virtual gboolean removeWordBefore (void) = 0;
+     virtual gboolean removeWordAfter (void) = 0;
+-    virtual gboolean moveCursorLeft (void) = 0;
+-    virtual gboolean moveCursorRight (void) = 0;
++    virtual gboolean moveCursorLeft (void);
++    virtual gboolean moveCursorRight (void);
+     virtual gboolean moveCursorLeftByWord (void) = 0;
+     virtual gboolean moveCursorRightByWord (void) = 0;
+-    virtual gboolean moveCursorToBegin (void) = 0;
+-    virtual gboolean moveCursorToEnd (void) = 0;
++    virtual gboolean moveCursorToBegin (void);
++    virtual gboolean moveCursorToEnd (void);
+     virtual void commit (void) = 0;
+     virtual void updateAuxiliaryText (void) = 0;
+     virtual void updatePreeditText (void) = 0;
+-- 
+1.7.6.4
+
+
+From d372fbc3c073d37496be1571fdd6a0fec86307ea Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Wed, 28 Sep 2011 17:35:18 +0800
+Subject: [PATCH 45/71] re-factor pinyin editor
+
+---
+ src/PYPPinyinEditor.cc |   73 +-----------------------------------------------
+ src/PYPPinyinEditor.h  |    6 ----
+ 2 files changed, 1 insertions(+), 78 deletions(-)
+
+diff --git a/src/PYPPinyinEditor.cc b/src/PYPPinyinEditor.cc
+index 5599416..817f621 100644
+--- a/src/PYPPinyinEditor.cc
++++ b/src/PYPPinyinEditor.cc
+@@ -298,34 +298,7 @@ LibPinyinPinyinEditor::updateLookupTable ()
+     LibPinyinPhoneticEditor::updateLookupTable ();
+ }
+ 
+-gboolean
+-LibPinyinPinyinEditor::removeCharBefore (void)
+-{
+-    if (G_UNLIKELY (m_cursor == 0))
+-        return FALSE;
+-
+-    m_cursor --;
+-    m_text.erase (m_cursor, 1);
+-
+-    updatePinyin ();
+-    update ();
+-
+-    return TRUE;
+-}
+-
+-gboolean
+-LibPinyinPinyinEditor::removeCharAfter (void)
+-{
+-    if (G_UNLIKELY (m_cursor == m_text.length ()))
+-        return FALSE;
+-
+-    m_text.erase (m_cursor, 1);
+-
+-    updatePinyin ();
+-    update ();
+-
+-    return TRUE;
+-}
++/* move cursor functions */
+ 
+ guint
+ LibPinyinPinyinEditor::getCursorLeftByWord (void)
+@@ -398,28 +371,6 @@ LibPinyinPinyinEditor::removeWordAfter (void)
+ }
+ 
+ gboolean
+-LibPinyinPinyinEditor::moveCursorLeft (void)
+-{
+-    if (G_UNLIKELY (m_cursor == 0))
+-        return FALSE;
+-
+-    m_cursor --;
+-    update ();
+-    return TRUE;
+-}
+-
+-gboolean
+-LibPinyinPinyinEditor::moveCursorRight (void)
+-{
+-    if (G_UNLIKELY (m_cursor == m_text.length ()))
+-        return FALSE;
+-
+-    m_cursor ++;
+-    update ();
+-    return TRUE;
+-}
+-
+-gboolean
+ LibPinyinPinyinEditor::moveCursorLeftByWord (void)
+ {
+     if (G_UNLIKELY (m_cursor == 0))
+@@ -444,25 +395,3 @@ LibPinyinPinyinEditor::moveCursorRightByWord (void)
+     update ();
+     return TRUE;
+ }
+-
+-gboolean
+-LibPinyinPinyinEditor::moveCursorToBegin (void)
+-{
+-    if (G_UNLIKELY (m_cursor == 0))
+-        return TRUE;
+-
+-    m_cursor = 0;
+-    update ();
+-    return TRUE;
+-}
+-
+-gboolean
+-LibPinyinPinyinEditor::moveCursorToEnd (void)
+-{
+-    if (G_UNLIKELY (m_cursor == m_text.length ()))
+-        return FALSE;
+-
+-    m_cursor = m_text.length ();
+-    update ();
+-    return TRUE;
+-}
+diff --git a/src/PYPPinyinEditor.h b/src/PYPPinyinEditor.h
+index 974d2a5..87fe210 100644
+--- a/src/PYPPinyinEditor.h
++++ b/src/PYPPinyinEditor.h
+@@ -36,17 +36,11 @@ public:
+     LibPinyinPinyinEditor (PinyinProperties & props, Config & config);
+ 
+ public:
+-    gboolean removeCharBefore (void);
+-    gboolean removeCharAfter (void);
+     gboolean removeWordBefore (void);
+     gboolean removeWordAfter (void);
+ 
+-    gboolean moveCursorLeft (void);
+-    gboolean moveCursorRight (void);
+     gboolean moveCursorLeftByWord (void);
+     gboolean moveCursorRightByWord (void);
+-    gboolean moveCursorToBegin (void);
+-    gboolean moveCursorToEnd (void);
+ 
+ 
+ protected:
+-- 
+1.7.6.4
+
+
+From a87fbe8b02845f67eec4443abb5eee373579c999 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Wed, 28 Sep 2011 17:51:56 +0800
+Subject: [PATCH 46/71] polish code
+
+---
+ src/PYPPinyinEngine.cc |   29 +++++++++--------------------
+ src/PYPPinyinEngine.h  |    2 ++
+ 2 files changed, 11 insertions(+), 20 deletions(-)
+
+diff --git a/src/PYPPinyinEngine.cc b/src/PYPPinyinEngine.cc
+index 2877702..f8e20ee 100644
+--- a/src/PYPPinyinEngine.cc
++++ b/src/PYPPinyinEngine.cc
+@@ -46,7 +46,9 @@ LibPinyinPinyinEngine::LibPinyinPinyinEngine (IBusEngine *engine)
+ {
+     gint i;
+ 
+-    if (PinyinConfig::instance ().doublePinyin ())
++    m_double_pinyin = PinyinConfig::instance ().doublePinyin ();
++
++    if (m_double_pinyin)
+         m_editors[MODE_INIT].reset
+             (new LibPinyinDoublePinyinEditor (m_props, PinyinConfig::instance ()));
+     else
+@@ -148,23 +150,7 @@ LibPinyinPinyinEngine::processKeyEvent (guint keyval, guint keycode, guint modif
+ #endif
+                 }
+             } else {
+-                if (m_prev_pressed_key != IBUS_period) {
+-                    if ((keyval == IBUS_at || keyval == IBUS_colon)) {
+-                        m_input_mode = MODE_RAW;
+-                        m_editors[MODE_RAW]->setText (text, text.length ());
+-                        m_editors[MODE_INIT]->reset ();
+-                    }
+-                }
+-                else {
+-                    if ((keyval >= IBUS_a && keyval <= IBUS_z) ||
+-                        (keyval >= IBUS_A && keyval <= IBUS_Z)) {
+-                        String tmp = text;
+-                        tmp += ".";
+-                        m_input_mode = MODE_RAW;
+-                        m_editors[MODE_RAW]->setText (tmp, tmp.length ());
+-                        m_editors[MODE_INIT]->reset ();
+-                    }
+-                }
++                g_assert_not_reached ();
+             }
+         }
+         retval = m_editors[m_input_mode]->processKeyEvent (keyval, keycode, modifiers);
+@@ -189,17 +175,20 @@ LibPinyinPinyinEngine::focusIn (void)
+     /* TODO: check memory leak here,
+      *       or switch full/double pinyin when pinyin config is changed.*/
+     if (PinyinConfig::instance ().doublePinyin ()) {
+-        if (dynamic_cast <LibPinyinDoublePinyinEditor *> (m_editors[MODE_INIT].get ()) == NULL) {
++        if (!m_double_pinyin) {
+             m_editors[MODE_INIT].reset (new LibPinyinDoublePinyinEditor (m_props, PinyinConfig::instance ()));
+             connectEditorSignals (m_editors[MODE_INIT]);
+         }
++        m_double_pinyin = TRUE;
+     }
+     else {
+-        if (dynamic_cast <LibPinyinFullPinyinEditor *> (m_editors[MODE_INIT].get ()) == NULL) {
++        if (m_double_pinyin) {
+             m_editors[MODE_INIT].reset (new LibPinyinFullPinyinEditor (m_props, PinyinConfig::instance ()));
+             connectEditorSignals (m_editors[MODE_INIT]);
+         }
++        m_double_pinyin = FALSE;
+     }
++
+     registerProperties (m_props.properties ());
+ }
+ 
+diff --git a/src/PYPPinyinEngine.h b/src/PYPPinyinEngine.h
+index d8040c1..7a2d635 100644
+--- a/src/PYPPinyinEngine.h
++++ b/src/PYPPinyinEngine.h
+@@ -70,6 +70,8 @@ private:
+         MODE_LAST,
+     } m_input_mode;
+ 
++    gboolean m_double_pinyin;
++
+     EditorPtr m_editors[MODE_LAST];
+     EditorPtr m_fallback_editor;
+ 
+-- 
+1.7.6.4
+
+
+From a7fa96bf9d0081b3b85fe8177a1b51268267d9e4 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Thu, 29 Sep 2011 10:28:25 +0800
+Subject: [PATCH 47/71] fixes libpinyin pinyin engine
+
+---
+ src/PYPPinyinEngine.cc |    4 +++-
+ 1 files changed, 3 insertions(+), 1 deletions(-)
+
+diff --git a/src/PYPPinyinEngine.cc b/src/PYPPinyinEngine.cc
+index f8e20ee..1fc4933 100644
+--- a/src/PYPPinyinEngine.cc
++++ b/src/PYPPinyinEngine.cc
+@@ -149,7 +149,7 @@ LibPinyinPinyinEngine::processKeyEvent (guint keyval, guint keycode, guint modif
+                     break;
+ #endif
+                 }
+-            } else {
++            } else { /* Unknown */
+                 g_assert_not_reached ();
+             }
+         }
+@@ -277,10 +277,12 @@ LibPinyinPinyinEngine::commitText (Text & text)
+     Engine::commitText (text);
+     if (m_input_mode != MODE_INIT)
+         m_input_mode = MODE_INIT;
++#if 0
+     if (text.text ())
+         static_cast<FallbackEditor*> (m_fallback_editor.get ())->setPrevCommittedChar (*text.text ());
+     else
+         static_cast<FallbackEditor*> (m_fallback_editor.get ())->setPrevCommittedChar (0);
++#endif
+ }
+ 
+ void
+-- 
+1.7.6.4
+
+
+From f94b146760628458572483726768faa5cf5cf756 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Thu, 29 Sep 2011 11:03:50 +0800
+Subject: [PATCH 48/71] re-factor libpinyin backend
+
+---
+ src/PYLibPinyin.cc |   22 ++++++++++++++++------
+ src/PYLibPinyin.h  |    3 +++
+ src/PYMain.cc      |    3 +++
+ 3 files changed, 22 insertions(+), 6 deletions(-)
+
+diff --git a/src/PYLibPinyin.cc b/src/PYLibPinyin.cc
+index 8e3d7af..e4d1b84 100644
+--- a/src/PYLibPinyin.cc
++++ b/src/PYLibPinyin.cc
+@@ -29,15 +29,25 @@ std::unique_ptr<LibPinyinBackEnd> LibPinyinBackEnd::m_instance;
+ 
+ static LibPinyinBackEnd libpinyin_backend;
+ 
+-LibPinyinBackEnd::LibPinyinBackEnd(){
+-    g_assert (NULL == m_instance.get ());
+-    m_pinyin_context = pinyin_init("/usr/share/libpinyin/data", "../data");
+-    m_instance.reset(this);
++LibPinyinBackEnd::LibPinyinBackEnd () {
++    m_pinyin_context = pinyin_init ("/usr/share/libpinyin/data", NULL);
++    m_chewing_context = pinyin_init ("/usr/share/libpinyin/data", NULL);
+ }
+ 
+-LibPinyinBackEnd::~LibPinyinBackEnd(){
++LibPinyinBackEnd::~LibPinyinBackEnd () {
+     pinyin_fini(m_pinyin_context);
+-    m_instance = NULL;
++    pinyin_fini(m_chewing_context);
++}
++
++void
++LibPinyinBackEnd::init (void) {
++    g_assert (NULL == m_instance.get ());
++    LibPinyinBackEnd * backend = new LibPinyinBackEnd;
++    m_instance.reset(backend);
++}
++
++void
++LibPinyinBackEnd::finalize (void) {
+ }
+ 
+ /* Here are the fuzzy pinyin options conversion table. */
+diff --git a/src/PYLibPinyin.h b/src/PYLibPinyin.h
+index 3d40b1d..212bf53 100644
+--- a/src/PYLibPinyin.h
++++ b/src/PYLibPinyin.h
+@@ -41,6 +41,9 @@ public:
+     /* use static initializer in C++. */
+     static LibPinyinBackEnd & instance (void) { return *m_instance; }
+ 
++    static void init (void);
++    static void finalize (void);
++
+ protected:
+     gboolean setFuzzyOptions (Config *config, pinyin_context_t *context);
+ 
+diff --git a/src/PYMain.cc b/src/PYMain.cc
+index 021201f..a19a5bf 100644
+--- a/src/PYMain.cc
++++ b/src/PYMain.cc
+@@ -30,6 +30,7 @@
+ #include "PYBus.h"
+ #include "PYConfig.h"
+ #include "PYDatabase.h"
++#include "PYLibPinyin.h"
+ 
+ using namespace PY;
+ 
+@@ -83,6 +84,7 @@ start_component (void)
+     Database::init ();
+     PinyinConfig::init (bus);
+     BopomofoConfig::init (bus);
++    LibPinyinBackEnd::init ();
+ 
+     g_signal_connect ((IBusBus *)bus, "disconnected", G_CALLBACK (ibus_disconnected_cb), NULL);
+ 
+@@ -143,6 +145,7 @@ sigterm_cb (int sig)
+ static void
+ atexit_cb (void)
+ {
++    LibPinyinBackEnd::finalize ();
+     PY::Database::finalize ();
+ }
+ 
+-- 
+1.7.6.4
+
+
+From 5f27536c62860b9436bd38ad509b195c26c1a288 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Thu, 29 Sep 2011 13:46:48 +0800
+Subject: [PATCH 49/71] add PYPBopomofoEngine.h
+
+---
+ src/Makefile.am         |    1 +
+ src/PYPBopomofoEngine.h |   84 +++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 85 insertions(+), 0 deletions(-)
+ create mode 100644 src/PYPBopomofoEngine.h
+
+diff --git a/src/Makefile.am b/src/Makefile.am
+index fc73a9b..e3c8026 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -120,6 +120,7 @@ ibus_engine_pinyin_h_sources = \
+ 	PYPDoublePinyinEditor.h \
+ 	PYPBopomofoEditor.h \
+ 	PYPPinyinEngine.h \
++	PYPBopomofoEngine.h \
+ 	$(NULL)
+ 
+ if IBUS_BUILD_LUA_EXTENSION
+diff --git a/src/PYPBopomofoEngine.h b/src/PYPBopomofoEngine.h
+new file mode 100644
+index 0000000..f767908
+--- /dev/null
++++ b/src/PYPBopomofoEngine.h
+@@ -0,0 +1,84 @@
++/* vim:set et ts=4 sts=4:
++ *
++ * ibus-pinyin - The Chinese PinYin engine for IBus
++ *
++ * Copyright (c) 2008-2010 Peng Huang <shawn.p.huang at gmail.com>
++ * Copyright (c) 2010 BYVoid <byvoid1 at gmail.com>
++ * Copyright (c) 2011 Peng Wu <alexepico at gmail.com>
++ *
++ * 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.
++ */
++#ifndef __PY_LIB_PINYIN_BOPOMOFO_ENGINE_H_
++#define __PY_LIB_PINYIN_BOPOMOFO_ENGINE_H_
++
++#include "PYEngine.h"
++#include "PYPinyinProperties.h"
++
++namespace PY {
++
++class LibPinyinBopomofoEngine : public Engine {
++public:
++    LibPinyinBopomofoEngine (IBusEngine *engine);
++    ~LibPinyinBopomofoEngine (void);
++
++    // virtual functions
++    gboolean processKeyEvent (guint keyval, guint keycode, guint modifiers);
++    void focusIn (void);
++    void focusOut (void);
++    void reset (void);
++    void enable (void);
++    void disable (void);
++    void pageUp (void);
++    void pageDown (void);
++    void cursorUp (void);
++    void cursorDown (void);
++    gboolean propertyActivate (const gchar *prop_name, guint prop_state);
++    void candidateClicked (guint index, guint button, guint state);
++
++private:
++    gboolean processPunct (guint keyval, guint keycode, guint modifiers);
++
++private:
++    void showSetupDialog (void);
++    void connectEditorSignals (EditorPtr editor);
++
++private:
++    void commitText (Text & text);
++
++private:
++    PinyinProperties m_props;
++
++    guint m_prev_pressed_key;
++
++    enum {
++        MODE_INIT = 0,          // init mode
++        MODE_PUNCT,             // punct mode
++#if 0
++        MODE_RAW,               // raw mode
++        MODE_ENGLISH,           // press v into English input mode
++        MODE_STROKE,            // press u into stroke input mode
++        MODE_EXTENSION,         // press i into extension input mode
++#endif
++        MODE_LAST,
++    } m_input_mode;
++
++    EditorPtr m_editors[MODE_LAST];
++    EditorPtr m_fallback_editor;
++};
++
++};
++
++
++#endif
+-- 
+1.7.6.4
+
+
+From a4d249bf8ed06be72eb667d12639a1ba77418d44 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Thu, 29 Sep 2011 14:59:44 +0800
+Subject: [PATCH 50/71] add PYPBopomofoEngine.cc
+
+---
+ src/Makefile.am          |    1 +
+ src/PYPBopomofoEngine.cc |  254 ++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 255 insertions(+), 0 deletions(-)
+ create mode 100644 src/PYPBopomofoEngine.cc
+
+diff --git a/src/Makefile.am b/src/Makefile.am
+index e3c8026..b2a2670 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -71,6 +71,7 @@ ibus_engine_pinyin_c_sources = \
+ 	PYPDoublePinyinEditor.cc \
+ 	PYPBopomofoEditor.cc \
+ 	PYPPinyinEngine.cc \
++	PYPBopomofoEngine.cc \
+ 	$(NULL)
+ ibus_engine_pinyin_h_sources = \
+ 	PYBopomofo.h \
+diff --git a/src/PYPBopomofoEngine.cc b/src/PYPBopomofoEngine.cc
+new file mode 100644
+index 0000000..e48e9af
+--- /dev/null
++++ b/src/PYPBopomofoEngine.cc
+@@ -0,0 +1,254 @@
++/* vim:set et ts=4 sts=4:
++ *
++ * ibus-pinyin - The Chinese PinYin engine for IBus
++ *
++ * Copyright (c) 2008-2010 Peng Huang <shawn.p.huang at gmail.com>
++ * Copyright (c) 2010 BYVoid <byvoid1 at gmail.com>
++ * Copyright (c) 2011 Peng Wu <alexepico at gmail.com>
++ *
++ * 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 "PYPBopomofoEngine.h"
++#include <string>
++#include "PYPunctEditor.h"
++#include "PYPBopomofoEditor.h"
++#include "PYFallbackEditor.h"
++#include "PYConfig.h"
++
++using namespace PY;
++
++/* constructor */
++LibPinyinBopomofoEngine::LibPinyinBopomofoEngine (IBusEngine *engine)
++    : Engine (engine),
++      m_props (BopomofoConfig::instance ()),
++      m_prev_pressed_key (IBUS_VoidSymbol),
++      m_input_mode (MODE_INIT),
++      m_fallback_editor (new FallbackEditor (m_props, BopomofoConfig::instance()))
++{
++    gint i;
++
++    /* create editors */
++    m_editors[MODE_INIT].reset (new LibPinyinBopomofoEditor (m_props, BopomofoConfig::instance ()));
++    m_editors[MODE_PUNCT].reset (new PunctEditor (m_props, BopomofoConfig::instance ()));
++
++    m_props.signalUpdateProperty ().connect
++        (std::bind (&LibPinyinBopomofoEngine::updateProperty, this, _1));
++
++    for (i = MODE_INIT; i < MODE_LAST; i++) {
++        connectEditorSignals (m_editors[i]);
++    }
++
++    connectEditorSignals (m_fallback_editor);
++}
++
++/* destructor */
++LibPinyinBopomofoEngine::~LibPinyinBopomofoEngine (void)
++{
++}
++
++gboolean
++LibPinyinBopomofoEngine::processKeyEvent (guint keyval, guint keycode, guint modifiers)
++{
++    gboolean retval = FALSE;
++
++    /* check Shift + Release hotkey,
++     * and then ignore other Release key event */
++    if (modifiers & IBUS_RELEASE_MASK) {
++        /* press and release keyval are same,
++         * and no other key event between the press and release key event */
++        if (m_prev_pressed_key == keyval) {
++            if (keyval == IBUS_Shift_L || keyval == IBUS_Shift_R) {
++                if (!m_editors[MODE_INIT]->text ().empty ())
++                    m_editors[MODE_INIT]->reset ();
++                m_props.toggleModeChinese ();
++                return TRUE;
++            }
++        }
++
++        if (m_input_mode == MODE_INIT &&
++            m_editors[MODE_INIT]->text ().empty ()) {
++            /* If it is init mode, and no any previous input text,
++             * we will let client applications to handle release key event */
++            return FALSE;
++        } else {
++            return TRUE;
++        }
++    }
++
++    /* Toggle simp/trad Chinese Mode when hotkey Ctrl + Shift + F pressed */
++    if (keyval == IBUS_F && scmshm_test (modifiers, (IBUS_SHIFT_MASK | IBUS_CONTROL_MASK))) {
++        m_props.toggleModeSimp();
++        m_prev_pressed_key = IBUS_F;
++        return TRUE;
++    }
++
++    if (m_props.modeChinese ()) {
++        if (G_UNLIKELY (m_input_mode == MODE_INIT &&
++                        m_editors[MODE_INIT]->text ().empty () &&
++                        cmshm_filter (modifiers) == 0 &&
++                        keyval == IBUS_grave)){
++            /* if BopomofoEditor is empty and get a grave key,
++             * switch current editor to PunctEditor */
++            m_input_mode = MODE_PUNCT;
++        }
++
++        retval = m_editors[m_input_mode]->processKeyEvent (keyval, keycode, modifiers);
++        if (G_UNLIKELY (retval &&
++                        m_input_mode != MODE_INIT &&
++                        m_editors[m_input_mode]->text ().empty ()))
++            m_input_mode = MODE_INIT;
++    }
++
++    if (G_UNLIKELY (!retval))
++        retval = m_fallback_editor->processKeyEvent (keyval, keycode, modifiers);
++
++    /* store ignored key event by editors */
++    m_prev_pressed_key = retval ? IBUS_VoidSymbol : keyval;
++
++    return retval;
++}
++
++void
++LibPinyinBopomofoEngine::focusIn (void)
++{
++    registerProperties (m_props.properties ());
++}
++
++void
++LibPinyinBopomofoEngine::focusOut (void)
++{
++    reset ();
++}
++
++void
++LibPinyinBopomofoEngine::reset (void)
++{
++    m_prev_pressed_key = IBUS_VoidSymbol;
++    m_input_mode = MODE_INIT;
++    for (gint i = 0; i < MODE_LAST; i++) {
++        m_editors[i]->reset ();
++    }
++    m_fallback_editor->reset ();
++}
++
++void
++LibPinyinBopomofoEngine::enable (void)
++{
++    m_props.reset ();
++}
++
++void
++LibPinyinBopomofoEngine::disable (void)
++{
++}
++
++void
++LibPinyinBopomofoEngine::pageUp (void)
++{
++    m_editors[m_input_mode]->pageUp ();
++}
++
++void
++LibPinyinBopomofoEngine::pageDown (void)
++{
++    m_editors[m_input_mode]->pageDown ();
++}
++
++void
++LibPinyinBopomofoEngine::cursorUp (void)
++{
++    m_editors[m_input_mode]->cursorUp ();
++}
++
++void
++LibPinyinBopomofoEngine::cursorDown (void)
++{
++    m_editors[m_input_mode]->cursorDown ();
++}
++
++inline void
++LibPinyinBopomofoEngine::showSetupDialog (void)
++{
++    g_assert (FALSE);
++}
++
++gboolean
++LibPinyinBopomofoEngine::propertyActivate (const gchar *prop_name,
++                                           guint prop_state)
++{
++    const static std::string setup ("setup");
++    if (m_props.propertyActivate (prop_name, prop_state)) {
++        return TRUE;
++    }
++    else if (setup == prop_name) {
++        showSetupDialog ();
++        return TRUE;
++    }
++    return FALSE;
++}
++
++void
++LibPinyinBopomofoEngine::candidateClicked (guint index,
++                                           guint button,
++                                           guint state)
++{
++    m_editors[m_input_mode]->candidateClicked (index, button, state);
++}
++
++void
++LibPinyinBopomofoEngine::commitText (Text & text)
++{
++    Engine::commitText (text);
++    if (m_input_mode != MODE_INIT)
++        m_input_mode = MODE_INIT;
++#if 0
++    if (text.text ())
++        static_cast<FallbackEditor*> (m_fallback_editor.get ())->setPrevCommittedChar (*text.text ());
++    else
++        static_cast<FallbackEditor*> (m_fallback_editor.get ())->setPrevCommittedChar (0);
++#endif
++}
++
++void
++LibPinyinBopomofoEngine::connectEditorSignals (EditorPtr editor)
++{
++    editor->signalCommitText ().connect (
++        std::bind (&LibPinyinBopomofoEngine::commitText, this, _1));
++
++    editor->signalUpdatePreeditText ().connect (
++        std::bind (&LibPinyinBopomofoEngine::updatePreeditText, this, _1, _2, _3));
++    editor->signalShowPreeditText ().connect (
++        std::bind (&LibPinyinBopomofoEngine::showPreeditText, this));
++    editor->signalHidePreeditText ().connect (
++        std::bind (&LibPinyinBopomofoEngine::hidePreeditText, this));
++
++    editor->signalUpdateAuxiliaryText ().connect (
++        std::bind (&LibPinyinBopomofoEngine::updateAuxiliaryText, this, _1, _2));
++    editor->signalShowAuxiliaryText ().connect (
++        std::bind (&LibPinyinBopomofoEngine::showAuxiliaryText, this));
++    editor->signalHideAuxiliaryText ().connect (
++        std::bind (&LibPinyinBopomofoEngine::hideAuxiliaryText, this));
++
++    editor->signalUpdateLookupTable ().connect (
++        std::bind (&LibPinyinBopomofoEngine::updateLookupTable, this, _1, _2));
++    editor->signalUpdateLookupTableFast ().connect (
++        std::bind (&LibPinyinBopomofoEngine::updateLookupTableFast, this, _1, _2));
++    editor->signalShowLookupTable ().connect (
++        std::bind (&LibPinyinBopomofoEngine::showLookupTable, this));
++    editor->signalHideLookupTable ().connect (
++        std::bind (&LibPinyinBopomofoEngine::hideLookupTable, this));
++}
++
++
+-- 
+1.7.6.4
+
+
+From fdb0faafb87135edb9ac6b9d25525dbc2f268f71 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Thu, 29 Sep 2011 15:08:52 +0800
+Subject: [PATCH 51/71] add libpinyin engines to PYEngine.cc
+
+---
+ src/PYEngine.cc |   25 ++++++++++++++++++++-----
+ 1 files changed, 20 insertions(+), 5 deletions(-)
+
+diff --git a/src/PYEngine.cc b/src/PYEngine.cc
+index 7987146..3a34afc 100644
+--- a/src/PYEngine.cc
++++ b/src/PYEngine.cc
+@@ -23,6 +23,8 @@
+ #include "PYEngine.h"
+ #include "PYPinyinEngine.h"
+ #include "PYBopomofoEngine.h"
++#include "PYPPinyinEngine.h"
++#include "PYPBopomofoEngine.h"
+ 
+ namespace PY {
+ /* code of engine class of GObject */
+@@ -155,11 +157,24 @@ ibus_pinyin_engine_constructor (GType                  type,
+                                                            construct_params);
+     name = ibus_engine_get_name ((IBusEngine *) engine);
+ 
+-    if (name && 
+-        (std::strcmp (name, "bopomofo") == 0 || std::strcmp (name, "bopomofo-debug") == 0)) {
+-        engine->engine = new BopomofoEngine (IBUS_ENGINE (engine));
+-    }
+-    else {
++    if (name) {
++        if (std::strcmp (name, "pinyin") == 0 ||
++            std::strcmp (name, "pinyin-debug") == 0) {
++            engine->engine = new PinyinEngine (IBUS_ENGINE (engine));
++        }
++        if (std::strcmp (name, "bopomofo") == 0 ||
++            std::strcmp (name, "bopomofo-debug") == 0) {
++            engine->engine = new BopomofoEngine (IBUS_ENGINE (engine));
++        }
++        if (std::strcmp (name, "libpinyin") == 0 ||
++            std::strcmp (name, "libpinyin-debug") == 0) {
++            engine->engine = new LibPinyinPinyinEngine (IBUS_ENGINE (engine));
++        }
++        if (std::strcmp (name, "libbopomofo") == 0 ||
++            std::strcmp (name, "libbopomofo") == 0 ) {
++            engine->engine = new LibPinyinBopomofoEngine (IBUS_ENGINE (engine));
++        }
++    } else {
+         engine->engine = new PinyinEngine (IBUS_ENGINE (engine));
+     }
+     return (GObject *) engine;
+-- 
+1.7.6.4
+
+
+From 485d515721c2127a9a1fa8996799cdbd900d1b72 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Fri, 30 Sep 2011 10:30:11 +0800
+Subject: [PATCH 52/71] add show setup
+
+---
+ src/PYPBopomofoEngine.cc |    3 ++-
+ src/PYPPinyinEngine.cc   |    6 +++---
+ 2 files changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/src/PYPBopomofoEngine.cc b/src/PYPBopomofoEngine.cc
+index e48e9af..a8ff6fc 100644
+--- a/src/PYPBopomofoEngine.cc
++++ b/src/PYPBopomofoEngine.cc
+@@ -181,7 +181,8 @@ LibPinyinBopomofoEngine::cursorDown (void)
+ inline void
+ LibPinyinBopomofoEngine::showSetupDialog (void)
+ {
+-    g_assert (FALSE);
++    g_spawn_command_line_async
++        (LIBEXECDIR"/ibus-setup-pinyin bopomofo --libpinyin", NULL);
+ }
+ 
+ gboolean
+diff --git a/src/PYPPinyinEngine.cc b/src/PYPPinyinEngine.cc
+index 1fc4933..c163cfc 100644
+--- a/src/PYPPinyinEngine.cc
++++ b/src/PYPPinyinEngine.cc
+@@ -150,7 +150,7 @@ LibPinyinPinyinEngine::processKeyEvent (guint keyval, guint keycode, guint modif
+ #endif
+                 }
+             } else { /* Unknown */
+-                g_assert_not_reached ();
++                g_warn_if_reached ();
+             }
+         }
+         retval = m_editors[m_input_mode]->processKeyEvent (keyval, keycode, modifiers);
+@@ -247,8 +247,8 @@ LibPinyinPinyinEngine::cursorDown (void)
+ inline void
+ LibPinyinPinyinEngine::showSetupDialog (void)
+ {
+-    /* TODO: to be implemented */
+-    g_assert (FALSE);
++    g_spawn_command_line_async
++        (LIBEXECDIR"/ibus-setup-pinyin pinyin --libpinyin", NULL);
+ }
+ 
+ gboolean
+-- 
+1.7.6.4
+
+
+From 0c6b69bce0c9bf0c79bd4d3db464e6c2eb8cb1e7 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Fri, 30 Sep 2011 10:54:25 +0800
+Subject: [PATCH 53/71] add lazy init
+
+---
+ src/PYLibPinyin.cc |   45 ++++++++++++++++++++++++++++++++++++++++-----
+ src/PYLibPinyin.h  |    5 +++++
+ 2 files changed, 45 insertions(+), 5 deletions(-)
+
+diff --git a/src/PYLibPinyin.cc b/src/PYLibPinyin.cc
+index e4d1b84..a7097fe 100644
+--- a/src/PYLibPinyin.cc
++++ b/src/PYLibPinyin.cc
+@@ -30,24 +30,59 @@ std::unique_ptr<LibPinyinBackEnd> LibPinyinBackEnd::m_instance;
+ static LibPinyinBackEnd libpinyin_backend;
+ 
+ LibPinyinBackEnd::LibPinyinBackEnd () {
+-    m_pinyin_context = pinyin_init ("/usr/share/libpinyin/data", NULL);
+-    m_chewing_context = pinyin_init ("/usr/share/libpinyin/data", NULL);
++    m_pinyin_context = NULL;
++    m_chewing_context = NULL;
+ }
+ 
+ LibPinyinBackEnd::~LibPinyinBackEnd () {
+-    pinyin_fini(m_pinyin_context);
+-    pinyin_fini(m_chewing_context);
++    if (m_pinyin_context)
++        pinyin_fini(m_pinyin_context);
++    m_pinyin_context = NULL;
++    if (m_chewing_context)
++        pinyin_fini(m_chewing_context);
++    m_chewing_context = NULL;
++}
++
++pinyin_instance_t *
++LibPinyinBackEnd::allocPinyinInstance ()
++{
++    if (NULL == m_pinyin_context) {
++        m_pinyin_context = pinyin_init ("/usr/share/libpinyin/data", NULL);
++    }
++    return pinyin_alloc_instance (m_pinyin_context);
++}
++
++void
++LibPinyinBackEnd::freePinyinInstance (pinyin_instance_t *instance)
++{
++    pinyin_free_instance (instance);
++}
++
++pinyin_instance_t *
++LibPinyinBackEnd::allocChewingInstance ()
++{
++    if (NULL == m_chewing_context) {
++        m_chewing_context = pinyin_init ("/usr/share/libpinyin/data", NULL);
++    }
++    return pinyin_alloc_instance (m_chewing_context);
++}
++
++void
++LibPinyinBackEnd::freeChewingInstance (pinyin_instance_t *instance)
++{
++    pinyin_free_instance (instance);
+ }
+ 
+ void
+ LibPinyinBackEnd::init (void) {
+     g_assert (NULL == m_instance.get ());
+     LibPinyinBackEnd * backend = new LibPinyinBackEnd;
+-    m_instance.reset(backend);
++    m_instance.reset (backend);
+ }
+ 
+ void
+ LibPinyinBackEnd::finalize (void) {
++    m_instance.reset ();
+ }
+ 
+ /* Here are the fuzzy pinyin options conversion table. */
+diff --git a/src/PYLibPinyin.h b/src/PYLibPinyin.h
+index 212bf53..44ed727 100644
+--- a/src/PYLibPinyin.h
++++ b/src/PYLibPinyin.h
+@@ -38,6 +38,11 @@ public:
+     gboolean setPinyinOptions (Config *config);
+     gboolean setChewingOptions (Config *config);
+ 
++    pinyin_instance_t *allocPinyinInstance ();
++    void freePinyinInstance (pinyin_instance_t *instance);
++    pinyin_instance_t *allocChewingInstance ();
++    void freeChewingInstance (pinyin_instance_t *instance);
++
+     /* use static initializer in C++. */
+     static LibPinyinBackEnd & instance (void) { return *m_instance; }
+ 
+-- 
+1.7.6.4
+
+
+From f1073c63e615ab2b7159937b586007a75a0b492a Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Fri, 7 Oct 2011 12:53:14 +0800
+Subject: [PATCH 54/71] write libpinyin backend
+
+---
+ src/PYLibPinyin.cc |   10 ++++++++++
+ 1 files changed, 10 insertions(+), 0 deletions(-)
+
+diff --git a/src/PYLibPinyin.cc b/src/PYLibPinyin.cc
+index a7097fe..d76e612 100644
+--- a/src/PYLibPinyin.cc
++++ b/src/PYLibPinyin.cc
+@@ -48,6 +48,7 @@ LibPinyinBackEnd::allocPinyinInstance ()
+ {
+     if (NULL == m_pinyin_context) {
+         m_pinyin_context = pinyin_init ("/usr/share/libpinyin/data", NULL);
++        setPinyinOptions (&PinyinConfig::instance ());
+     }
+     return pinyin_alloc_instance (m_pinyin_context);
+ }
+@@ -63,6 +64,7 @@ LibPinyinBackEnd::allocChewingInstance ()
+ {
+     if (NULL == m_chewing_context) {
+         m_chewing_context = pinyin_init ("/usr/share/libpinyin/data", NULL);
++        setChewingOptions (&BopomofoConfig::instance ());
+     }
+     return pinyin_alloc_instance (m_chewing_context);
+ }
+@@ -117,6 +119,8 @@ static const struct {
+ gboolean
+ LibPinyinBackEnd::setFuzzyOptions (Config *config, pinyin_context_t *context)
+ {
++    g_assert (context);
++
+     guint option = config->option ();
+     PinyinCustomSettings custom;
+ 
+@@ -151,6 +155,9 @@ static const struct{
+ gboolean
+ LibPinyinBackEnd::setPinyinOptions (Config *config)
+ {
++    if (NULL == m_pinyin_context)
++        return FALSE;
++
+     const gint map = config->doublePinyinSchema ();
+     for (guint i = 0; i < G_N_ELEMENTS (shuang_pin_options); i++) {
+         if (map == shuang_pin_options[i].double_pinyin_keyboard) {
+@@ -179,6 +186,9 @@ static const struct {
+ gboolean
+ LibPinyinBackEnd::setChewingOptions (Config *config)
+ {
++    if (NULL == m_chewing_context)
++        return FALSE;
++
+     const gint map = config->bopomofoKeyboardMapping ();
+     for (guint i = 0; i < G_N_ELEMENTS (chewing_options); i++) {
+         if (map == chewing_options[i].bopomofo_keyboard) {
+-- 
+1.7.6.4
+
+
+From a7efa0d82a7c4cae3a22f1f0e446ca5fff005ffd Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Fri, 7 Oct 2011 13:05:20 +0800
+Subject: [PATCH 55/71] write PYConfig
+
+---
+ src/PYConfig.cc |    7 +++++++
+ 1 files changed, 7 insertions(+), 0 deletions(-)
+
+diff --git a/src/PYConfig.cc b/src/PYConfig.cc
+index 1373607..9e539c8 100644
+--- a/src/PYConfig.cc
++++ b/src/PYConfig.cc
+@@ -23,6 +23,7 @@
+ #include "PYTypes.h"
+ #include "PYBus.h"
+ #include "PYDoublePinyinTable.h"
++#include "PYLibPinyin.h"
+ 
+ namespace PY {
+ 
+@@ -336,6 +337,12 @@ Config::valueChangedCallback (IBusConfig  *config,
+                               Config      *self)
+ {
+     self->valueChanged (section, name, value);
++    if (self->m_section != section)
++        return;
++    if (self->m_section == "engine/Pinyin")
++        LibPinyinBackEnd::instance ().setPinyinOptions (self);
++    if (self->m_section == "engine/Bopomofo")
++        LibPinyinBackEnd::instance ().setChewingOptions (self);
+ }
+ 
+ static const struct {
+-- 
+1.7.6.4
+
+
+From a73a74a6c1ecb79b7fde223e1e71e6cbec04c802 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Sat, 8 Oct 2011 10:03:26 +0800
+Subject: [PATCH 56/71] alloc/free pinyin instance
+
+---
+ src/PYMain.cc                |    2 +-
+ src/PYPBopomofoEditor.cc     |    4 ++++
+ src/PYPDoublePinyinEditor.cc |    8 ++++++++
+ src/PYPDoublePinyinEditor.h  |    1 +
+ src/PYPFullPinyinEditor.cc   |    4 ++++
+ src/PYPPinyinEditor.h        |    2 --
+ 6 files changed, 18 insertions(+), 3 deletions(-)
+
+diff --git a/src/PYMain.cc b/src/PYMain.cc
+index a19a5bf..c4895ec 100644
+--- a/src/PYMain.cc
++++ b/src/PYMain.cc
+@@ -82,9 +82,9 @@ start_component (void)
+     }
+ 
+     Database::init ();
++    LibPinyinBackEnd::init ();
+     PinyinConfig::init (bus);
+     BopomofoConfig::init (bus);
+-    LibPinyinBackEnd::init ();
+ 
+     g_signal_connect ((IBusBus *)bus, "disconnected", G_CALLBACK (ibus_disconnected_cb), NULL);
+ 
+diff --git a/src/PYPBopomofoEditor.cc b/src/PYPBopomofoEditor.cc
+index 1945183..f13fcc9 100644
+--- a/src/PYPBopomofoEditor.cc
++++ b/src/PYPBopomofoEditor.cc
+@@ -20,6 +20,7 @@
+  */
+ #include "PYPBopomofoEditor.h"
+ #include "PYConfig.h"
++#include "PYLibPinyin.h"
+ #include "PYPinyinProperties.h"
+ #include "PYSimpTradConverter.h"
+ #include "PYHalfFullConverter.h"
+@@ -48,10 +49,13 @@ LibPinyinBopomofoEditor::LibPinyinBopomofoEditor
+     : LibPinyinPhoneticEditor (props, config),
+       m_select_mode (FALSE)
+ {
++    m_instance = LibPinyinBackEnd::instance ().allocChewingInstance ();
+ }
+ 
+ LibPinyinBopomofoEditor::~LibPinyinBopomofoEditor (void)
+ {
++    LibPinyinBackEnd::instance ().freeChewingInstance (m_instance);
++    m_instance = NULL;
+ }
+ 
+ void
+diff --git a/src/PYPDoublePinyinEditor.cc b/src/PYPDoublePinyinEditor.cc
+index d37a480..8db80a4 100644
+--- a/src/PYPDoublePinyinEditor.cc
++++ b/src/PYPDoublePinyinEditor.cc
+@@ -21,6 +21,7 @@
+ 
+ #include "PYPDoublePinyinEditor.h"
+ #include "PYConfig.h"
++#include "PYLibPinyin.h"
+ 
+ #define DEFINE_DOUBLE_PINYIN_TABLES
+ #include "PYDoublePinyinTable.h"
+@@ -48,6 +49,13 @@ LibPinyinDoublePinyinEditor::LibPinyinDoublePinyinEditor
+ ( PinyinProperties & props, Config & config)
+     : LibPinyinPinyinEditor (props, config)
+ {
++    m_instance = LibPinyinBackEnd::instance ().allocPinyinInstance ();
++}
++
++LibPinyinDoublePinyinEditor::~LibPinyinDoublePinyinEditor (void)
++{
++    LibPinyinBackEnd::instance ().freePinyinInstance (m_instance);
++    m_instance = NULL;
+ }
+ 
+ gboolean
+diff --git a/src/PYPDoublePinyinEditor.h b/src/PYPDoublePinyinEditor.h
+index b06e144..0989a24 100644
+--- a/src/PYPDoublePinyinEditor.h
++++ b/src/PYPDoublePinyinEditor.h
+@@ -29,6 +29,7 @@ class LibPinyinDoublePinyinEditor : public LibPinyinPinyinEditor {
+ 
+ public:
+     LibPinyinDoublePinyinEditor (PinyinProperties & props, Config & config);
++    ~LibPinyinDoublePinyinEditor (void);
+ 
+     gboolean insert (gint ch);
+ 
+diff --git a/src/PYPFullPinyinEditor.cc b/src/PYPFullPinyinEditor.cc
+index 064ae40..f07204b 100644
+--- a/src/PYPFullPinyinEditor.cc
++++ b/src/PYPFullPinyinEditor.cc
+@@ -21,6 +21,7 @@
+ 
+ #include "PYPFullPinyinEditor.h"
+ #include "PYConfig.h"
++#include "PYLibPinyin.h"
+ 
+ using namespace PY;
+ 
+@@ -28,10 +29,13 @@ LibPinyinFullPinyinEditor::LibPinyinFullPinyinEditor
+ (PinyinProperties & props, Config & config)
+     : LibPinyinPinyinEditor (props, config)
+ {
++    m_instance = LibPinyinBackEnd::instance ().allocPinyinInstance ();
+ }
+ 
+ LibPinyinFullPinyinEditor::~LibPinyinFullPinyinEditor (void)
+ {
++    LibPinyinBackEnd::instance ().freePinyinInstance (m_instance);
++    m_instance = NULL;
+ }
+ 
+ void
+diff --git a/src/PYPPinyinEditor.h b/src/PYPPinyinEditor.h
+index 87fe210..3c61918 100644
+--- a/src/PYPPinyinEditor.h
++++ b/src/PYPPinyinEditor.h
+@@ -29,8 +29,6 @@ namespace PY {
+ 
+ class Config;
+ 
+-class SpecialPhraseTable;
+-
+ class LibPinyinPinyinEditor : public LibPinyinPhoneticEditor {
+ public:
+     LibPinyinPinyinEditor (PinyinProperties & props, Config & config);
+-- 
+1.7.6.4
+
+
+From d4baea8eb96460c50d241933713b0e419a9abddf Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Sat, 8 Oct 2011 10:11:35 +0800
+Subject: [PATCH 57/71] add engines
+
+---
+ src/PYMain.cc |   32 +++++++++++++++++++++++++++++++-
+ 1 files changed, 31 insertions(+), 1 deletions(-)
+
+diff --git a/src/PYMain.cc b/src/PYMain.cc
+index c4895ec..3516b90 100644
+--- a/src/PYMain.cc
++++ b/src/PYMain.cc
+@@ -103,7 +103,8 @@ start_component (void)
+                                                      "zh_CN",
+                                                      "GPL",
+                                                      "Peng Huang <shawn.p.huang at gmail.com>\n"
+-                                                     "BYVoid <byvoid1 at gmail.com>",
++                                                     "BYVoid <byvoid1 at gmail.com>\n"
++                                                     "Peng Wu <alexepico at gmail.com>",
+                                                      PKGDATADIR "/icons/ibus-pinyin.svg",
+                                                      "us"));
+     ibus_component_add_engine (component,
+@@ -113,20 +114,49 @@ start_component (void)
+                                                      "zh_CN",
+                                                      "GPL",
+                                                      "BYVoid <byvoid1 at gmail.com>\n"
++                                                     "Peng Huang <shawn.p.huang at gmail.com>\n"
++                                                     "Peng Wu <alexepico at gmail.com>",
++                                                     PKGDATADIR "/icons/ibus-bopomofo.svg",
++                                                     "us"));
++
++    ibus_component_add_engine (component,
++                               ibus_engine_desc_new ("libpinyin-debug",
++                                                     N_("Intelligent Pinyin (debug)"),
++                                                     N_("Intelligent Pinyin input method (debug)"),
++                                                     "zh_CN",
++                                                     "GPL",
++                                                     "Peng Huang <shawn.p.huang at gmail.com>\n"
++                                                     "Peng Wu <alexepico at gmail.com>\n"
++                                                     "BYVoid <byvoid1 at gmail.com>",
++                                                     PKGDATADIR "/icons/ibus-pinyin.svg",
++                                                     "us"));
++    ibus_component_add_engine (component,
++                               ibus_engine_desc_new ("libbopomofo-debug",
++                                                     N_("Intelligent Bopomofo (debug)"),
++                                                     N_("Intelligent Bopomofo input method (debug)"),
++                                                     "zh_CN",
++                                                     "GPL",
++                                                     "BYVoid <byvoid1 at gmail.com>\n"
++                                                     "Peng Wu <alexepico at gmail.com>\n"
+                                                      "Peng Huang <shawn.p.huang at gmail.com>",
+                                                      PKGDATADIR "/icons/ibus-bopomofo.svg",
+                                                      "us"));
+ 
++
+     factory = ibus_factory_new (ibus_bus_get_connection (bus));
+ 
+     if (ibus) {
+         ibus_factory_add_engine (factory, "pinyin", IBUS_TYPE_PINYIN_ENGINE);
+         ibus_factory_add_engine (factory, "bopomofo", IBUS_TYPE_PINYIN_ENGINE);
++        ibus_factory_add_engine (factory, "libpinyin", IBUS_TYPE_PINYIN_ENGINE);
++        ibus_factory_add_engine (factory, "libbopomofo", IBUS_TYPE_PINYIN_ENGINE);
+         ibus_bus_request_name (bus, "org.freedesktop.IBus.Pinyin", 0);
+     }
+     else {
+         ibus_factory_add_engine (factory, "pinyin-debug", IBUS_TYPE_PINYIN_ENGINE);
+         ibus_factory_add_engine (factory, "bopomofo-debug", IBUS_TYPE_PINYIN_ENGINE);
++        ibus_factory_add_engine (factory, "libpinyin-debug", IBUS_TYPE_PINYIN_ENGINE);
++        ibus_factory_add_engine (factory, "libbopomofo-debug", IBUS_TYPE_PINYIN_ENGINE);
+         ibus_bus_register_component (bus, component);
+     }
+ 
+-- 
+1.7.6.4
+
+
+From 33a08c7702e7bdf816cd4e9a21fd8190d2cbc35d Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Sat, 8 Oct 2011 10:37:40 +0800
+Subject: [PATCH 58/71] fixes full editor
+
+---
+ src/PYPFullPinyinEditor.cc |    5 ++++-
+ src/PYPPhoneticEditor.cc   |    3 +++
+ src/PYPPinyinEngine.cc     |    4 ++--
+ 3 files changed, 9 insertions(+), 3 deletions(-)
+
+diff --git a/src/PYPFullPinyinEditor.cc b/src/PYPFullPinyinEditor.cc
+index f07204b..0b7d603 100644
+--- a/src/PYPFullPinyinEditor.cc
++++ b/src/PYPFullPinyinEditor.cc
+@@ -122,12 +122,15 @@ LibPinyinFullPinyinEditor::updateAuxiliaryText ()
+ 
+         if (G_UNLIKELY (cursor == m_cursor)) { /* at word boundary. */
+             m_buffer << '|' << key->get_key_string ();
+-        } else { /* in word */
++        } else if (G_LIKELY ( cursor < m_cursor &&
++                              m_cursor < pos->get_end_pos() )) { /* in word */
+             /* raw text */
+             String raw = m_text.substr (cursor, pos->get_length ());
+             guint offset = m_cursor - cursor;
+             m_buffer << ' ' << raw.substr (0, offset)
+                      << '|' << raw.substr (offset);
++        } else { /* other words */
++            m_buffer << ' ' << key->get_key_string ();
+         }
+     }
+ 
+diff --git a/src/PYPPhoneticEditor.cc b/src/PYPPhoneticEditor.cc
+index 6fde250..14773a7 100644
+--- a/src/PYPPhoneticEditor.cc
++++ b/src/PYPPhoneticEditor.cc
+@@ -32,6 +32,7 @@ LibPinyinPhoneticEditor::LibPinyinPhoneticEditor (PinyinProperties &props,
+     m_pinyin_len (0),
+     m_lookup_table (m_config.pageSize ())
+ {
++    m_candidates = g_array_new(FALSE, TRUE, sizeof(phrase_token_t));
+ }
+ 
+ gboolean
+@@ -281,6 +282,8 @@ LibPinyinPhoneticEditor::reset (void)
+ void
+ LibPinyinPhoneticEditor::update (void)
+ {
++    guint pinyin_cursor = getPinyinCursor ();
++    pinyin_get_candidates (m_instance, pinyin_cursor, m_candidates);
+     updateLookupTable ();
+     updatePreeditText ();
+     updateAuxiliaryText ();
+diff --git a/src/PYPPinyinEngine.cc b/src/PYPPinyinEngine.cc
+index c163cfc..4aae9a9 100644
+--- a/src/PYPPinyinEngine.cc
++++ b/src/PYPPinyinEngine.cc
+@@ -149,8 +149,8 @@ LibPinyinPinyinEngine::processKeyEvent (guint keyval, guint keycode, guint modif
+                     break;
+ #endif
+                 }
+-            } else { /* Unknown */
+-                g_warn_if_reached ();
++            } else {
++                /* TODO: Unknown */
+             }
+         }
+         retval = m_editors[m_input_mode]->processKeyEvent (keyval, keycode, modifiers);
+-- 
+1.7.6.4
+
+
+From 1d4b7682ac6e05758e2d9dd45b373d48903568b1 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Sat, 8 Oct 2011 11:29:03 +0800
+Subject: [PATCH 59/71] fixes double pinyin
+
+---
+ src/PYPDoublePinyinEditor.cc |    8 +++++++-
+ src/PYPFullPinyinEditor.cc   |    3 +++
+ 2 files changed, 10 insertions(+), 1 deletions(-)
+
+diff --git a/src/PYPDoublePinyinEditor.cc b/src/PYPDoublePinyinEditor.cc
+index 8db80a4..4ea039e 100644
+--- a/src/PYPDoublePinyinEditor.cc
++++ b/src/PYPDoublePinyinEditor.cc
+@@ -138,15 +138,21 @@ LibPinyinDoublePinyinEditor::updateAuxiliaryText (void)
+ 
+         if (G_UNLIKELY (cursor == m_cursor)) { /* at word boundary. */
+             m_buffer << '|' << key->get_key_string ();
+-        } else { /* in word */
++        } else if (G_LIKELY ( cursor < m_cursor &&
++                              m_cursor < pos->get_end_pos() )) { /* in word */
+             /* raw text */
+             String raw = m_text.substr (cursor, pos->get_length ());
+             guint offset = m_cursor - cursor;
+             m_buffer << ' ' << raw.substr (0, offset)
+                      << '|' << raw.substr (offset);
++        } else { /* other words */
++            m_buffer << ' ' << key->get_key_string ();
+         }
+     }
+ 
++    if (m_cursor == m_pinyin_len)
++        m_buffer << '|';
++
+     /* append rest text */
+     const gchar * p = m_text.c_str() + m_pinyin_len;
+     m_buffer << p;
+diff --git a/src/PYPFullPinyinEditor.cc b/src/PYPFullPinyinEditor.cc
+index 0b7d603..69ed5ab 100644
+--- a/src/PYPFullPinyinEditor.cc
++++ b/src/PYPFullPinyinEditor.cc
+@@ -134,6 +134,9 @@ LibPinyinFullPinyinEditor::updateAuxiliaryText ()
+         }
+     }
+ 
++    if (m_cursor == m_pinyin_len)
++        m_buffer << '|';
++
+     /* append rest text */
+     const gchar * p = m_text.c_str() + m_pinyin_len;
+     m_buffer << p;
+-- 
+1.7.6.4
+
+
+From de6e93108fc2c3b2ce3b8fba522a3edad082b738 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Sat, 8 Oct 2011 11:40:11 +0800
+Subject: [PATCH 60/71] fixes chewing editor
+
+---
+ src/PYEngine.cc          |    2 +-
+ src/PYPBopomofoEditor.cc |    8 +++++++-
+ 2 files changed, 8 insertions(+), 2 deletions(-)
+
+diff --git a/src/PYEngine.cc b/src/PYEngine.cc
+index 3a34afc..27cc312 100644
+--- a/src/PYEngine.cc
++++ b/src/PYEngine.cc
+@@ -171,7 +171,7 @@ ibus_pinyin_engine_constructor (GType                  type,
+             engine->engine = new LibPinyinPinyinEngine (IBUS_ENGINE (engine));
+         }
+         if (std::strcmp (name, "libbopomofo") == 0 ||
+-            std::strcmp (name, "libbopomofo") == 0 ) {
++            std::strcmp (name, "libbopomofo-debug") == 0 ) {
+             engine->engine = new LibPinyinBopomofoEngine (IBUS_ENGINE (engine));
+         }
+     } else {
+diff --git a/src/PYPBopomofoEditor.cc b/src/PYPBopomofoEditor.cc
+index f13fcc9..1a330cc 100644
+--- a/src/PYPBopomofoEditor.cc
++++ b/src/PYPBopomofoEditor.cc
+@@ -351,7 +351,8 @@ LibPinyinBopomofoEditor::updateAuxiliaryText (void)
+ 
+         if (G_UNLIKELY (cursor == m_cursor)) { /* at word boundary. */
+             m_buffer << '|' << key->get_key_zhuyin_string ();
+-        } else { /* in word */
++        } else if (G_LIKELY ( cursor < m_cursor &&
++                              m_cursor < pos->get_end_pos() )) { /* in word */
+             /* raw text */
+             String raw = m_text.substr (cursor, pos->get_length ());
+             guint offset = m_cursor - cursor;
+@@ -366,9 +367,14 @@ LibPinyinBopomofoEditor::updateAuxiliaryText (void)
+             for ( iter = after.begin (); iter != after.end (); ++iter) {
+                 m_buffer << bopomofo_char[keyvalToBopomofo (*iter)];
+             }
++        } else { /* other words */
++            m_buffer << ' ' << key->get_key_zhuyin_string ();
+         }
+     }
+ 
++    if (m_cursor == m_pinyin_len)
++        m_buffer << '|';
++
+     /* append rest text */
+     const gchar * p = m_text.c_str() + m_pinyin_len;
+     m_buffer << p;
+-- 
+1.7.6.4
+
+
+From fd277418074f4ee9c587f95cf93ce83bb71bb4ce Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Sat, 8 Oct 2011 18:53:12 +0800
+Subject: [PATCH 61/71] add to pinyin.xml.in.in
+
+---
+ src/pinyin.xml.in.in |   28 ++++++++++++++++++++++++++++
+ 1 files changed, 28 insertions(+), 0 deletions(-)
+
+diff --git a/src/pinyin.xml.in.in b/src/pinyin.xml.in.in
+index 94b803a..f8ada12 100644
+--- a/src/pinyin.xml.in.in
++++ b/src/pinyin.xml.in.in
+@@ -37,6 +37,34 @@ Peng Wu &lt;alexepico at gmail.com&gt;</author>
+ 			<description>Bopomofo input method</description>
+ 			<rank>98</rank>
+ 		</engine>
++		<engine>
++			<name>libpinyin</name>
++			<language>zh</language>
++			<license>GPL</license>
++			<author>Peng Huang &lt;shawn.p.huang at gmail.com&gt;
++                        Peng Wu &lt;alexepico at gmail.com&gt;
++                        BYVoid &lt;byvoid1 at gmail.com&gt;
++                        </author>
++			<icon>${pkgdatadir}/icons/ibus-pinyin.svg</icon>
++			<layout>us</layout>
++			<longname>Intelligent Pinyin</longname>
++			<description>Intelligent Pinyin input method</description>
++			<rank>99</rank>
++		</engine>
++		<engine>
++			<name>libbopomofo</name>
++			<language>zh</language>
++			<license>GPL</license>
++			<author>BYVoid &lt;byvoid1 at gmail.com&gt;
++                        Peng Wu &lt;alexepico at gmail.com&gt;
++                        Peng Huang &lt;shawn.p.huang at gmail.com&gt;
++                        </author>
++			<icon>${pkgdatadir}/icons/ibus-bopomofo.svg</icon>
++			<layout>us</layout>
++			<longname>Intelligent Bopomofo</longname>
++			<description>Intelligent Bopomofo input method</description>
++			<rank>98</rank>
++		</engine>
+ 	</engines>
+ 
+ </component>
+-- 
+1.7.6.4
+
+
+From 2451a4c83885e796d7ddfee9d0321d56bc3703ef Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Sat, 8 Oct 2011 19:01:16 +0800
+Subject: [PATCH 62/71] fixes update preedit text
+
+---
+ src/PYPBopomofoEditor.cc |   14 ++++++++------
+ src/PYPPinyinEditor.cc   |   14 ++++++++------
+ 2 files changed, 16 insertions(+), 12 deletions(-)
+
+diff --git a/src/PYPBopomofoEditor.cc b/src/PYPBopomofoEditor.cc
+index 1a330cc..185fdb3 100644
+--- a/src/PYPBopomofoEditor.cc
++++ b/src/PYPBopomofoEditor.cc
+@@ -311,13 +311,15 @@ LibPinyinBopomofoEditor::updatePreeditText ()
+     m_buffer.clear ();
+     char *tmp = NULL;
+     pinyin_get_sentence(m_instance, &tmp);
+-    if (m_props.modeSimp ()) {
+-        m_buffer<<tmp;
+-    } else {
+-        SimpTradConverter::simpToTrad (tmp, m_buffer);
++    if (tmp) {
++        if (m_props.modeSimp ()) {
++            m_buffer<<tmp;
++        } else {
++            SimpTradConverter::simpToTrad (tmp, m_buffer);
++        }
++        g_free (tmp);
++        tmp = NULL;
+     }
+-    g_free (tmp);
+-    tmp = NULL;
+ 
+     /* append rest text */
+     const gchar *p = m_text.c_str () + m_pinyin_len;
+diff --git a/src/PYPPinyinEditor.cc b/src/PYPPinyinEditor.cc
+index 817f621..3d7deff 100644
+--- a/src/PYPPinyinEditor.cc
++++ b/src/PYPPinyinEditor.cc
+@@ -242,13 +242,15 @@ LibPinyinPinyinEditor::updatePreeditText ()
+     m_buffer.clear ();
+     char *tmp = NULL;
+     pinyin_get_sentence(m_instance, &tmp);
+-    if (m_props.modeSimp ()) {
+-        m_buffer<<tmp;
+-    } else {
+-        SimpTradConverter::simpToTrad (tmp, m_buffer);
++    if (tmp) {
++        if (m_props.modeSimp ()) {
++            m_buffer<<tmp;
++        } else {
++            SimpTradConverter::simpToTrad (tmp, m_buffer);
++        }
++        g_free (tmp);
++        tmp = NULL;
+     }
+-    g_free (tmp);
+-    tmp = NULL;
+ 
+     /* append rest text */
+     const gchar *p = m_text.c_str () + m_pinyin_len;
+-- 
+1.7.6.4
+
+
+From 83bd966f202824cbb431a581fea626f1252ce96e Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Mon, 10 Oct 2011 13:08:27 +0800
+Subject: [PATCH 63/71] update main.py
+
+---
+ setup/main.py |   21 +++++++++++++++------
+ 1 files changed, 15 insertions(+), 6 deletions(-)
+
+diff --git a/setup/main.py b/setup/main.py
+index 0e3a729..197ea8b 100644
+--- a/setup/main.py
++++ b/setup/main.py
+@@ -31,12 +31,13 @@ from xdg import BaseDirectory
+ _ = lambda a : gettext.dgettext("ibus-pinyin", a)
+ 
+ class PreferencesDialog:
+-    def __init__(self,engine):
++    def __init__(self,engine,libpinyin):
+         locale.setlocale(locale.LC_ALL, "")
+         localedir = os.getenv("IBUS_LOCALEDIR")
+         gettext.bindtextdomain("ibus-pinyin", localedir)
+         gettext.bind_textdomain_codeset("ibus-pinyin", "UTF-8")
+ 
++        self.__libpinyin = libpinyin
+         self.__bus = ibus.Bus()
+         self.__config = self.__bus.get_config()
+         self.__builder = gtk.Builder()
+@@ -50,14 +51,16 @@ class PreferencesDialog:
+             self.__init_general()
+             self.__init_pinyin()
+             self.__init_fuzzy()
+-            self.__init_dictionary()
++            if not self.__libpinyin:
++                self.__init_dictionary()
+             self.__init_about()
+         elif engine == "bopomofo":
+             self.__config_namespace = "engine/Bopomofo"
+             self.__init_general()
+             self.__init_bopomofo()
+             self.__init_fuzzy()
+-            self.__init_dictionary()
++            if not self.__libpinyin:
++                self.__init_dictionary()
+             self.__init_about()
+             self.__convert_fuzzy_pinyin_to_bopomofo()
+             
+@@ -138,6 +141,8 @@ class PreferencesDialog:
+         self.__double_pinyin_schema = self.__builder.get_object("DoublePinyinSchema")
+         # self.__double_pinyin_schema_label = self.__builder.get_object("labelDoublePinyinSchema")
+         self.__double_pinyin_show_raw = self.__builder.get_object("DoublePinyinShowRaw")
++        if self.__libpinyin:
++            self.__double_pinyin_show_raw.hide ()
+ 
+         renderer = gtk.CellRendererText()
+         self.__double_pinyin_schema.pack_start(renderer)
+@@ -409,11 +414,15 @@ class PreferencesDialog:
+ 
+ def main():
+     name = "pinyin"
+-    if len(sys.argv) == 2:
+-        name = sys.argv[1]
++    libpinyin = False
++    for arg in sys.argv[1:]:
++        if arg == "--libpinyin":
++            libpinyin = True
++        else:
++            name = arg
+     if name not in ("pinyin", "bopomofo"):
+         name = "pinyin"
+-    PreferencesDialog(name).run()
++    PreferencesDialog(name, libpinyin).run()
+ 
+ 
+ if __name__ == "__main__":
+-- 
+1.7.6.4
+
+
+From 6ecd8e73f2d5d035f36c5083aa8e69dbf198c671 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Mon, 10 Oct 2011 14:08:17 +0800
+Subject: [PATCH 64/71] add update when select candidate
+
+---
+ src/PYPBopomofoEditor.cc |    2 ++
+ src/PYPPhoneticEditor.cc |    3 ++-
+ src/PYPPinyinEditor.cc   |    3 ++-
+ 3 files changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/src/PYPBopomofoEditor.cc b/src/PYPBopomofoEditor.cc
+index 185fdb3..34f3df7 100644
+--- a/src/PYPBopomofoEditor.cc
++++ b/src/PYPBopomofoEditor.cc
+@@ -134,6 +134,7 @@ LibPinyinBopomofoEditor::processAuxiliarySelectKey
+     m_select_mode = TRUE;
+     selectCandidateInPage (i);
+ 
++    update ();
+     return TRUE;
+ }
+ 
+@@ -162,6 +163,7 @@ LibPinyinBopomofoEditor::processSelectKey (guint keyval, guint keycode,
+     guint i = pos - keys;
+     selectCandidateInPage (i);
+ 
++    update ();
+     return TRUE;
+ }
+ 
+diff --git a/src/PYPPhoneticEditor.cc b/src/PYPPhoneticEditor.cc
+index 14773a7..a5d7675 100644
+--- a/src/PYPPhoneticEditor.cc
++++ b/src/PYPPhoneticEditor.cc
+@@ -320,7 +320,8 @@ LibPinyinPhoneticEditor::selectCandidate (guint i)
+ 
+     /* NOTE: deal with normal candidates selection here by libpinyin. */
+     phrase_token_t *token = &g_array_index (m_candidates, phrase_token_t, i);
+-    pinyin_choose_candidate(m_instance, pinyin_cursor, *token);
++    pinyin_choose_candidate (m_instance, pinyin_cursor, *token);
++    pinyin_guess_sentence (m_instance);
+     return TRUE;
+ }
+ 
+diff --git a/src/PYPPinyinEditor.cc b/src/PYPPinyinEditor.cc
+index 3d7deff..4b8aa21 100644
+--- a/src/PYPPinyinEditor.cc
++++ b/src/PYPPinyinEditor.cc
+@@ -57,7 +57,7 @@ LibPinyinPinyinEditor::processNumber (guint keyval, guint keycode,
+ {
+     guint i;
+ 
+-    if (!m_text)
++    if (m_text.empty ())
+         return FALSE;
+ 
+     switch (keyval) {
+@@ -78,6 +78,7 @@ LibPinyinPinyinEditor::processNumber (guint keyval, guint keycode,
+     if (modifiers == 0)
+         selectCandidateInPage (i);
+ 
++    update ();
+     return TRUE;
+ }
+ 
+-- 
+1.7.6.4
+
+
+From 8c5d9452dba95acae0adfd06769f262f18614041 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Mon, 10 Oct 2011 15:25:20 +0800
+Subject: [PATCH 65/71] fixes commit/reset
+
+---
+ src/PYPPhoneticEditor.cc |    1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+
+diff --git a/src/PYPPhoneticEditor.cc b/src/PYPPhoneticEditor.cc
+index a5d7675..c50b265 100644
+--- a/src/PYPPhoneticEditor.cc
++++ b/src/PYPPhoneticEditor.cc
+@@ -275,6 +275,7 @@ LibPinyinPhoneticEditor::reset (void)
+ {
+     m_pinyin_len = 0;
+     m_lookup_table.clear ();
++    pinyin_reset (m_instance);
+ 
+     Editor::reset ();
+ }
+-- 
+1.7.6.4
+
+
+From 4ecd95e7e241ab53934483b36bb7fba2717afc54 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Mon, 10 Oct 2011 17:30:39 +0800
+Subject: [PATCH 66/71] fixes space handle
+
+---
+ src/PYPPhoneticEditor.cc |    7 ++-----
+ src/PYPPinyinEditor.cc   |    2 ++
+ 2 files changed, 4 insertions(+), 5 deletions(-)
+
+diff --git a/src/PYPPhoneticEditor.cc b/src/PYPPhoneticEditor.cc
+index c50b265..dc494d5 100644
+--- a/src/PYPPhoneticEditor.cc
++++ b/src/PYPPhoneticEditor.cc
+@@ -43,11 +43,8 @@ LibPinyinPhoneticEditor::processSpace (guint keyval, guint keycode,
+         return FALSE;
+     if (cmshm_filter (modifiers) != 0)
+         return TRUE;
+-    if (m_lookup_table.size () != 0) {
+-        selectCandidate (m_lookup_table.cursorPos ());
+-    } else {
+-        commit ();
+-    }
++
++    commit ();
+     return TRUE;
+ }
+ 
+diff --git a/src/PYPPinyinEditor.cc b/src/PYPPinyinEditor.cc
+index 4b8aa21..195d0e3 100644
+--- a/src/PYPPinyinEditor.cc
++++ b/src/PYPPinyinEditor.cc
+@@ -121,6 +121,7 @@ LibPinyinPinyinEditor::processPunct (guint keyval, guint keycode,
+         break;
+     }
+ 
++#if 0
+     if (m_config.autoCommit ()) {
+         if (m_lookup_table.size ()) {
+             /* TODO: check here. */
+@@ -129,6 +130,7 @@ LibPinyinPinyinEditor::processPunct (guint keyval, guint keycode,
+         commit ();
+         return FALSE;
+     }
++#endif
+ 
+     return TRUE;
+ }
+-- 
+1.7.6.4
+
+
+From 9a5d9bdde8bb12ac38af7a1eb2b7bb73a1ccf3ff Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Tue, 11 Oct 2011 11:14:18 +0800
+Subject: [PATCH 67/71] fixes choose candidate
+
+---
+ src/PYPPhoneticEditor.cc |    8 +++++++-
+ 1 files changed, 7 insertions(+), 1 deletions(-)
+
+diff --git a/src/PYPPhoneticEditor.cc b/src/PYPPhoneticEditor.cc
+index dc494d5..6be7079 100644
+--- a/src/PYPPhoneticEditor.cc
++++ b/src/PYPPhoneticEditor.cc
+@@ -318,8 +318,14 @@ LibPinyinPhoneticEditor::selectCandidate (guint i)
+ 
+     /* NOTE: deal with normal candidates selection here by libpinyin. */
+     phrase_token_t *token = &g_array_index (m_candidates, phrase_token_t, i);
+-    pinyin_choose_candidate (m_instance, pinyin_cursor, *token);
++    guint8 len = pinyin_choose_candidate (m_instance, pinyin_cursor, *token);
+     pinyin_guess_sentence (m_instance);
++
++    pinyin_cursor += len;
++    PinyinKeyPos *pos = &g_array_index
++        (m_instance->m_pinyin_poses, PinyinKeyPos, pinyin_cursor);
++    m_cursor = pos->get_pos();
++
+     return TRUE;
+ }
+ 
+-- 
+1.7.6.4
+
+
+From a4054b39925e3c194d6e8dddad6bbc403dd74ac0 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Tue, 25 Oct 2011 14:11:13 +0800
+Subject: [PATCH 68/71] update pinyin.xml.in.in
+
+---
+ src/pinyin.xml.in.in |   10 ++++++++--
+ 1 files changed, 8 insertions(+), 2 deletions(-)
+
+diff --git a/src/pinyin.xml.in.in b/src/pinyin.xml.in.in
+index f8ada12..d2b267d 100644
+--- a/src/pinyin.xml.in.in
++++ b/src/pinyin.xml.in.in
+@@ -47,10 +47,13 @@ Peng Wu &lt;alexepico at gmail.com&gt;</author>
+                         </author>
+ 			<icon>${pkgdatadir}/icons/ibus-pinyin.svg</icon>
+ 			<layout>us</layout>
+-			<longname>Intelligent Pinyin</longname>
++			<longname>Intelligent Pinyin(Beta)</longname>
+ 			<description>Intelligent Pinyin input method</description>
+ 			<rank>99</rank>
++                        @IBUS_HOTKEYS_XML@
++                        @IBUS_SYMBOL_XML@
+ 		</engine>
++<!--
+ 		<engine>
+ 			<name>libbopomofo</name>
+ 			<language>zh</language>
+@@ -61,10 +64,13 @@ Peng Wu &lt;alexepico at gmail.com&gt;</author>
+                         </author>
+ 			<icon>${pkgdatadir}/icons/ibus-bopomofo.svg</icon>
+ 			<layout>us</layout>
+-			<longname>Intelligent Bopomofo</longname>
++			<longname>Intelligent Bopomofo(Beta)</longname>
+ 			<description>Intelligent Bopomofo input method</description>
+ 			<rank>98</rank>
++                        @IBUS_HOTKEYS_XML@
++                        @IBUS_SYMBOL_XML@
+ 		</engine>
++-->
+ 	</engines>
+ 
+ </component>
+-- 
+1.7.6.4
+
+
+From 4c36af48e4a173a7008d2742fbdf1e0a97481c1b Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Tue, 25 Oct 2011 14:36:36 +0800
+Subject: [PATCH 69/71] add user data directory support
+
+---
+ src/PYLibPinyin.cc |   16 +++++++++++++++-
+ 1 files changed, 15 insertions(+), 1 deletions(-)
+
+diff --git a/src/PYLibPinyin.cc b/src/PYLibPinyin.cc
+index d76e612..077e7e0 100644
+--- a/src/PYLibPinyin.cc
++++ b/src/PYLibPinyin.cc
+@@ -47,8 +47,15 @@ pinyin_instance_t *
+ LibPinyinBackEnd::allocPinyinInstance ()
+ {
+     if (NULL == m_pinyin_context) {
+-        m_pinyin_context = pinyin_init ("/usr/share/libpinyin/data", NULL);
++        gchar * userdir = g_build_filename (g_get_home_dir(), ".cache",
++                                            "ibus", "libpinyin", NULL);
++        int retval = g_mkdir_with_parents (userdir, 0700);
++        if (retval) {
++            g_free(userdir); userdir = NULL;
++        }
++        m_pinyin_context = pinyin_init ("/usr/share/libpinyin/data", userdir);
+         setPinyinOptions (&PinyinConfig::instance ());
++        g_free(userdir);
+     }
+     return pinyin_alloc_instance (m_pinyin_context);
+ }
+@@ -63,8 +70,15 @@ pinyin_instance_t *
+ LibPinyinBackEnd::allocChewingInstance ()
+ {
+     if (NULL == m_chewing_context) {
++        gchar * userdir = g_build_filename (g_get_home_dir(), ".cache",
++                                            "ibus", "libbopomofo", NULL);
++        int retval = g_mkdir_with_parents (userdir, 0700);
++        if (retval) {
++            g_free(userdir); userdir = NULL;
++        }
+         m_chewing_context = pinyin_init ("/usr/share/libpinyin/data", NULL);
+         setChewingOptions (&BopomofoConfig::instance ());
++        g_free(userdir);
+     }
+     return pinyin_alloc_instance (m_chewing_context);
+ }
+-- 
+1.7.6.4
+
+
+From e4f2fa619027b987645b0c5e5cf4d5d152c67306 Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Wed, 26 Oct 2011 10:10:58 +0800
+Subject: [PATCH 70/71] add save support
+
+---
+ src/PYLibPinyin.cc       |   51 ++++++++++++++++++++++++++++++++++++++++++++++
+ src/PYLibPinyin.h        |    8 +++++++
+ src/PYPBopomofoEditor.cc |    1 +
+ src/PYPPinyinEditor.cc   |    2 +
+ 4 files changed, 62 insertions(+), 0 deletions(-)
+
+diff --git a/src/PYLibPinyin.cc b/src/PYLibPinyin.cc
+index 077e7e0..062b3c9 100644
+--- a/src/PYLibPinyin.cc
++++ b/src/PYLibPinyin.cc
+@@ -23,6 +23,8 @@
+ #include "PYTypes.h"
+ #include "PYConfig.h"
+ 
++#define LIBPINYIN_SAVE_TIMEOUT   (5 * 60)
++
+ using namespace PY;
+ 
+ std::unique_ptr<LibPinyinBackEnd> LibPinyinBackEnd::m_instance;
+@@ -30,11 +32,19 @@ std::unique_ptr<LibPinyinBackEnd> LibPinyinBackEnd::m_instance;
+ static LibPinyinBackEnd libpinyin_backend;
+ 
+ LibPinyinBackEnd::LibPinyinBackEnd () {
++    m_timeout_id = 0;
++    m_timer = g_timer_new();
+     m_pinyin_context = NULL;
+     m_chewing_context = NULL;
+ }
+ 
+ LibPinyinBackEnd::~LibPinyinBackEnd () {
++    g_timer_destroy (m_timer);
++    if (m_timeout_id != 0) {
++        saveUserDB ();
++        g_source_remove (m_timeout_id);
++    }
++
+     if (m_pinyin_context)
+         pinyin_fini(m_pinyin_context);
+     m_pinyin_context = NULL;
+@@ -215,3 +225,44 @@ LibPinyinBackEnd::setChewingOptions (Config *config)
+     setFuzzyOptions (config, m_chewing_context);
+     return TRUE;
+ }
++
++void
++LibPinyinBackEnd::modified (void)
++{
++    /* Restart the timer */
++    g_timer_start (m_timer);
++
++    if (m_timeout_id != 0)
++        return;
++
++    m_timeout_id = g_timeout_add_seconds (LIBPINYIN_SAVE_TIMEOUT,
++                                          LibPinyinBackEnd::timeoutCallback,
++                                          static_cast<gpointer> (this));
++}
++
++gboolean
++LibPinyinBackEnd::timeoutCallback (gpointer data)
++{
++    LibPinyinBackEnd *self = static_cast<LibPinyinBackEnd *> (data);
++
++    /* Get the elapsed time since last modification of database. */
++    guint elapsed = (guint)g_timer_elapsed (self->m_timer, NULL);
++
++    if (elapsed >= LIBPINYIN_SAVE_TIMEOUT &&
++        self->saveUserDB ()) {
++        self->m_timeout_id = 0;
++        return FALSE;
++    }
++
++    return TRUE;
++}
++
++gboolean
++LibPinyinBackEnd::saveUserDB (void)
++{
++    if (m_pinyin_context)
++        pinyin_save (m_pinyin_context);
++    if (m_chewing_context)
++        pinyin_save (m_chewing_context);
++    return TRUE;
++}
+diff --git a/src/PYLibPinyin.h b/src/PYLibPinyin.h
+index 44ed727..32919b9 100644
+--- a/src/PYLibPinyin.h
++++ b/src/PYLibPinyin.h
+@@ -42,6 +42,7 @@ public:
+     void freePinyinInstance (pinyin_instance_t *instance);
+     pinyin_instance_t *allocChewingInstance ();
+     void freeChewingInstance (pinyin_instance_t *instance);
++    void modified (void);
+ 
+     /* use static initializer in C++. */
+     static LibPinyinBackEnd & instance (void) { return *m_instance; }
+@@ -53,10 +54,17 @@ protected:
+     gboolean setFuzzyOptions (Config *config, pinyin_context_t *context);
+ 
+ private:
++    gboolean saveUserDB (void);
++    static gboolean timeoutCallback (gpointer data);
++
++private:
+     /* libpinyin context */
+     pinyin_context_t *m_pinyin_context;
+     pinyin_context_t *m_chewing_context;
+ 
++    guint m_timeout_id;
++    GTimer *m_timer;
++
+ private:
+     static std::unique_ptr<LibPinyinBackEnd> m_instance;
+ };
+diff --git a/src/PYPBopomofoEditor.cc b/src/PYPBopomofoEditor.cc
+index 34f3df7..7592e2a 100644
+--- a/src/PYPBopomofoEditor.cc
++++ b/src/PYPBopomofoEditor.cc
+@@ -297,6 +297,7 @@ LibPinyinBopomofoEditor::commit ()
+     }
+ 
+     pinyin_train(m_instance);
++    LibPinyinBackEnd::instance ().modified();
+     LibPinyinPhoneticEditor::commit ((const gchar *)m_buffer);
+     reset();
+ }
+diff --git a/src/PYPPinyinEditor.cc b/src/PYPPinyinEditor.cc
+index 195d0e3..e676f6d 100644
+--- a/src/PYPPinyinEditor.cc
++++ b/src/PYPPinyinEditor.cc
+@@ -24,6 +24,7 @@
+ #include "PYPinyinProperties.h"
+ #include "PYSimpTradConverter.h"
+ #include "PYHalfFullConverter.h"
++#include "PYLibPinyin.h"
+ 
+ using namespace PY;
+ 
+@@ -229,6 +230,7 @@ LibPinyinPinyinEditor::commit ()
+     }
+ 
+     pinyin_train(m_instance);
++    LibPinyinBackEnd::instance ().modified ();
+     LibPinyinPhoneticEditor::commit ((const gchar *)m_buffer);
+     reset();
+ }
+-- 
+1.7.6.4
+
+
+From 025580e8f4ad1d758729e467e73011046fdba64b Mon Sep 17 00:00:00 2001
+From: Peng Wu <alexepico at gmail.com>
+Date: Thu, 27 Oct 2011 11:36:59 +0800
+Subject: [PATCH 71/71] hide bopomofo
+
+---
+ src/pinyin.xml.in.in |   23 ++++-------------------
+ 1 files changed, 4 insertions(+), 19 deletions(-)
+
+diff --git a/src/pinyin.xml.in.in b/src/pinyin.xml.in.in
+index d2b267d..93b14a1 100644
+--- a/src/pinyin.xml.in.in
++++ b/src/pinyin.xml.in.in
+@@ -23,6 +23,8 @@ Peng Wu &lt;alexepico at gmail.com&gt;</author>
+ 			<longname>Pinyin</longname>
+ 			<description>Pinyin input method</description>
+ 			<rank>99</rank>
++                        @IBUS_HOTKEYS_XML@
++                        @IBUS_SYMBOL_XML@
+ 		</engine>
+ 		<engine>
+ 			<name>bopomofo</name>
+@@ -36,6 +38,8 @@ Peng Wu &lt;alexepico at gmail.com&gt;</author>
+ 			<longname>Bopomofo</longname>
+ 			<description>Bopomofo input method</description>
+ 			<rank>98</rank>
++                        @IBUS_HOTKEYS_XML@
++                        @IBUS_SYMBOL_XML@
+ 		</engine>
+ 		<engine>
+ 			<name>libpinyin</name>
+@@ -53,24 +57,5 @@ Peng Wu &lt;alexepico at gmail.com&gt;</author>
+                         @IBUS_HOTKEYS_XML@
+                         @IBUS_SYMBOL_XML@
+ 		</engine>
+-<!--
+-		<engine>
+-			<name>libbopomofo</name>
+-			<language>zh</language>
+-			<license>GPL</license>
+-			<author>BYVoid &lt;byvoid1 at gmail.com&gt;
+-                        Peng Wu &lt;alexepico at gmail.com&gt;
+-                        Peng Huang &lt;shawn.p.huang at gmail.com&gt;
+-                        </author>
+-			<icon>${pkgdatadir}/icons/ibus-bopomofo.svg</icon>
+-			<layout>us</layout>
+-			<longname>Intelligent Bopomofo(Beta)</longname>
+-			<description>Intelligent Bopomofo input method</description>
+-			<rank>98</rank>
+-                        @IBUS_HOTKEYS_XML@
+-                        @IBUS_SYMBOL_XML@
+-		</engine>
+--->
+ 	</engines>
+-
+ </component>
+-- 
+1.7.6.4
+
diff --git a/ibus-pinyin-xx-icon-symbol.patch b/ibus-pinyin-xx-icon-symbol.patch
index 4ddec26..4b195eb 100644
--- a/ibus-pinyin-xx-icon-symbol.patch
+++ b/ibus-pinyin-xx-icon-symbol.patch
@@ -2,7 +2,7 @@ Index: ibus-pinyin-1.3.99.20110706/configure.ac
 ===================================================================
 --- ibus-pinyin-1.3.99.20110706.orig/configure.ac
 +++ ibus-pinyin-1.3.99.20110706/configure.ac
-@@ -141,6 +141,10 @@ AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GET
+@@ -146,6 +146,10 @@ AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GET
  
  AM_GLIB_GNU_GETTEXT
  
@@ -13,28 +13,6 @@ Index: ibus-pinyin-1.3.99.20110706/configure.ac
  # --enable-db-android
  AC_ARG_ENABLE(db-android,
      AS_HELP_STRING([--disable-db-android],
-Index: ibus-pinyin-1.3.99.20110706/src/pinyin.xml.in.in
-===================================================================
---- ibus-pinyin-1.3.99.20110706.orig/src/pinyin.xml.in.in
-+++ ibus-pinyin-1.3.99.20110706/src/pinyin.xml.in.in
-@@ -23,6 +23,8 @@ Peng Wu &lt;alexepico at gmail.com&gt;</aut
- 			<longname>Pinyin</longname>
- 			<description>Pinyin input method</description>
- 			<rank>99</rank>
-+			@IBUS_HOTKEYS_XML@
-+			@IBUS_SYMBOL_XML@
- 		</engine>
- 		<engine>
- 			<name>bopomofo</name>
-@@ -36,6 +38,8 @@ Peng Wu &lt;alexepico at gmail.com&gt;</aut
- 			<longname>Bopomofo</longname>
- 			<description>Bopomofo input method</description>
- 			<rank>98</rank>
-+			@IBUS_HOTKEYS_XML@
-+			@IBUS_SYMBOL_XML@
- 		</engine>
- 	</engines>
- 
 Index: ibus-pinyin-1.3.99.20110706/m4/ibus.m4
 ===================================================================
 --- /dev/null
diff --git a/ibus-pinyin.spec b/ibus-pinyin.spec
index 26eceef..1829501 100644
--- a/ibus-pinyin.spec
+++ b/ibus-pinyin.spec
@@ -1,12 +1,13 @@
 Name:       ibus-pinyin
 Version:    1.3.99.20110706
-Release:    2%{?dist}
+Release:    3%{?dist}
 Summary:    The Chinese Pinyin and Bopomofo engines for IBus input platform
 License:    GPLv2+
 Group:      System Environment/Libraries
 URL:        http://code.google.com/p/ibus
 Source0:    http://ibus.googlecode.com/files/%{name}-%{version}.tar.gz
 Source1:    http://ibus.googlecode.com/files/pinyin-database-1.2.99.tar.bz2
+Patch0:     ibus-pinyin-libpinyin-integration.patch
 Patch1:     ibus-pinyin-xx-icon-symbol.patch
 
 BuildRoot:  %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
@@ -52,6 +53,7 @@ The phrase database for ibus Pinyin and Bopomofo from android project.
 
 %prep
 %setup -q
+%patch0 -p1 -b .integration
 %patch1 -p1 -b .xx-icon
 cp %{SOURCE1} data/db/open-phrase
 
@@ -108,6 +110,9 @@ rm -rf $RPM_BUILD_ROOT
 %{_datadir}/ibus-pinyin/db/android.db
 
 %changelog
+* Thu Oct 27 2011  Peng Wu <pwu at redhat.com> - 1.3.99.20110706-3
+- Add ibus-pinyin-libpinyin-integration.patch
+
 * Mon Aug 01 2011  Peng Wu <pwu at redhat.com> - 1.3.99.20110706-2
 - Add ibus-pinyin-xx-icon-symbol.patch
 


More information about the scm-commits mailing list