add Bopomofo Support
authorBYVoid <byvoid1@gmail.com>
Thu, 13 May 2010 03:18:30 +0000 (11:18 +0800)
committerBYVoid <byvoid1@gmail.com>
Thu, 13 May 2010 03:18:30 +0000 (11:18 +0800)
src/Bopomofo.h [new file with mode: 0644]
src/BopomofoEditor.cc [new file with mode: 0644]
src/BopomofoEditor.h [new file with mode: 0644]
src/Makefile.am
src/PinyinEditor.cc
src/PinyinEditor.h
src/PinyinEngine.cc
src/PinyinParser.cc
src/PinyinParser.h
src/PinyinParserTable.h

diff --git a/src/Bopomofo.h b/src/Bopomofo.h
new file mode 100644 (file)
index 0000000..37c2cb9
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Bopomofo.h
+ *
+ *  Created on: 2010-5-12
+ *      Author: byvoid
+ */
+
+#ifndef BOPOMOFO_H_
+#define BOPOMOFO_H_
+
+#define MAX_BOPOMOFO_LEN (4)
+
+#define BOPOMOFO_ZERO               (0)
+#define BOPOMOFO_B                  (1)
+#define BOPOMOFO_P                  (2)
+#define BOPOMOFO_M                  (3)
+#define BOPOMOFO_F                  (4)
+#define BOPOMOFO_D                  (5)
+#define BOPOMOFO_T                  (6)
+#define BOPOMOFO_N                  (7)
+#define BOPOMOFO_L                  (8)
+#define BOPOMOFO_G                  (9)
+#define BOPOMOFO_K                  (10)
+#define BOPOMOFO_H                  (11)
+#define BOPOMOFO_J                  (12)
+#define BOPOMOFO_Q                  (13)
+#define BOPOMOFO_X                  (14)
+#define BOPOMOFO_ZH                 (15)
+#define BOPOMOFO_CH                 (16)
+#define BOPOMOFO_SH                 (17)
+#define BOPOMOFO_R                  (18)
+#define BOPOMOFO_Z                  (19)
+#define BOPOMOFO_C                  (20)
+#define BOPOMOFO_S                  (21)
+#define BOPOMOFO_I                  (22)
+#define BOPOMOFO_U                  (23)
+#define BOPOMOFO_V                  (24)
+#define BOPOMOFO_A                  (25)
+#define BOPOMOFO_O                  (26)
+#define BOPOMOFO_E                  (27)
+#define BOPOMOFO_E2                 (28)
+#define BOPOMOFO_AI                 (29)
+#define BOPOMOFO_EI                 (30)
+#define BOPOMOFO_AO                 (31)
+#define BOPOMOFO_OU                 (32)
+#define BOPOMOFO_AN                 (33)
+#define BOPOMOFO_EN                 (34)
+#define BOPOMOFO_ANG                (35)
+#define BOPOMOFO_ENG                (36)
+#define BOPOMOFO_ER                 (37)
+#define BOPOMOFO_TONE_2             (38)
+#define BOPOMOFO_TONE_3             (39)
+#define BOPOMOFO_TONE_4             (40)
+#define BOPOMOFO_TONE_5             (41)
+
+const static wchar_t bopomofo_char[] = {
+    L'\0',L'ㄅ',L'ㄆ',L'ㄇ',L'ㄈ',L'ㄉ',L'ㄊ',L'ㄋ',L'ㄌ',L'ㄍ',L'ㄎ',
+    L'ㄏ',L'ㄐ',L'ㄑ',L'ㄒ',L'ㄓ',L'ㄔ',L'ㄕ',L'ㄖ',L'ㄗ',L'ㄘ',L'ㄙ',
+
+    L'ㄧ',L'ㄨ',L'ㄩ',L'ㄚ',L'ㄛ',L'ㄜ',L'ㄝ',L'ㄞ',L'ㄟ',L'ㄠ',L'ㄡ',
+    L'ㄢ',L'ㄣ',L'ㄤ',L'ㄥ',L'ㄦ',
+
+    L'ˊ',L'ˇ',L'ˋ',L'˙',
+};
+
+#endif /* BOPOMOFO_H_ */
diff --git a/src/BopomofoEditor.cc b/src/BopomofoEditor.cc
new file mode 100644 (file)
index 0000000..af5757e
--- /dev/null
@@ -0,0 +1,416 @@
+#include "Config.h"
+#include "BopomofoEditor.h"
+#include "SimpTradConverter.h"
+
+namespace PY {
+
+BopomofoEditor::BopomofoEditor (PinyinProperties & props)
+    : PinyinEditor (props)
+{
+}
+
+BopomofoEditor::~BopomofoEditor (void)
+{
+}
+
+void
+BopomofoEditor::reset (void)
+{
+    PinyinEditor::reset ();
+}
+
+gboolean
+BopomofoEditor::insert (gint ch)
+{
+    /* is full */
+    if (G_UNLIKELY (m_text.length () >= MAX_PINYIN_LEN))
+        return TRUE;
+
+    gint key = get_bopomofo_keyboard_map(ch);
+    if (key >= BOPOMOFO_TONE_2 && key <= BOPOMOFO_TONE_5) {
+        if (m_cursor == 0)
+            return TRUE;  /* invalid format: tone should not be the first character */
+        key = get_bopomofo_keyboard_map(m_text.c_str()[m_cursor - 1]);
+        if (key >= BOPOMOFO_TONE_2 && key <= BOPOMOFO_TONE_5)
+            return TRUE;  /* invalid format: two tone character should not be together  */
+    }
+
+    m_text.insert (m_cursor++, ch);
+
+    if (G_UNLIKELY (!(Config::option () & PINYIN_INCOMPLETE_PINYIN))) {
+        updateSpecialPhrases ();
+        updatePinyin ();
+    }
+    else if (G_LIKELY (m_cursor <= m_pinyin_len + 2)) {
+        updateSpecialPhrases ();
+        updatePinyin ();
+    }
+    else {
+        if (updateSpecialPhrases ()) {
+            update ();
+        }
+        else {
+            updatePreeditText ();
+            updateAuxiliaryText ();
+        }
+    }
+    return TRUE;
+}
+
+gboolean
+BopomofoEditor::removeCharBefore (void)
+{
+    if (G_UNLIKELY (m_cursor == 0))
+        return FALSE;
+
+    m_cursor --;
+    m_text.erase (m_cursor, 1);
+
+    updateSpecialPhrases ();
+    updatePinyin ();
+
+    return TRUE;
+}
+
+gboolean
+BopomofoEditor::removeCharAfter (void)
+{
+    if (G_UNLIKELY (m_cursor == m_text.length ()))
+        return FALSE;
+
+    m_text.erase (m_cursor, 1);
+    updatePreeditText ();
+    updateAuxiliaryText ();
+
+    return TRUE;
+}
+
+gboolean
+BopomofoEditor::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;
+    updateSpecialPhrases ();
+    updatePhraseEditor ();
+    update ();
+    return TRUE;
+}
+
+gboolean
+BopomofoEditor::removeWordAfter (void)
+{
+    if (G_UNLIKELY (m_cursor == m_text.length ()))
+        return FALSE;
+
+    m_text.erase (m_cursor, -1);
+    updatePreeditText ();
+    updateAuxiliaryText ();
+    return TRUE;
+}
+
+gboolean
+BopomofoEditor::moveCursorLeft (void)
+{
+    if (G_UNLIKELY (m_cursor == 0))
+        return FALSE;
+
+    m_cursor --;
+    updateSpecialPhrases ();
+    updatePinyin ();
+
+    return TRUE;
+}
+
+gboolean
+BopomofoEditor::moveCursorRight (void)
+{
+    if (G_UNLIKELY (m_cursor == m_text.length ()))
+        return FALSE;
+
+    m_cursor ++;
+
+    updateSpecialPhrases ();
+    updatePinyin ();
+
+    return TRUE;
+}
+
+gboolean
+BopomofoEditor::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 ();
+
+    updateSpecialPhrases ();
+    updatePhraseEditor ();
+    update ();
+
+    return TRUE;
+}
+
+gboolean
+BopomofoEditor::moveCursorRightByWord (void)
+{
+    return moveCursorToEnd ();
+}
+
+gboolean
+BopomofoEditor::moveCursorToBegin (void)
+{
+    if (G_UNLIKELY (m_cursor == 0))
+        return FALSE;
+
+    m_cursor = 0;
+    m_pinyin.clear ();
+    m_pinyin_len = 0;
+
+    updateSpecialPhrases ();
+    updatePhraseEditor ();
+    update ();
+
+    return TRUE;
+}
+
+gboolean
+BopomofoEditor::moveCursorToEnd (void)
+{
+    if (G_UNLIKELY (m_cursor == m_text.length ()))
+        return FALSE;
+
+    m_cursor = m_text.length ();
+    updateSpecialPhrases ();
+    updatePinyin ();
+
+    return TRUE;
+}
+
+gboolean
+BopomofoEditor::processKeyEvent (guint keyval, guint keycode, guint modifiers)
+{
+    switch (keyval) {
+    /* Bopomofo */
+    case IBUS_a ... IBUS_z:
+    case IBUS_0 ... IBUS_9:
+    case IBUS_comma:
+    case IBUS_period:
+    case IBUS_slash:
+    case IBUS_semicolon:
+    case IBUS_minus:
+        return processBopomofo (keyval, keycode, modifiers);
+
+    default:
+        return PinyinEditor::processKeyEvent (keyval, keycode, modifiers);
+    }
+}
+
+#define CMSHM_MASK              \
+        (IBUS_CONTROL_MASK |    \
+         IBUS_MOD1_MASK |       \
+         IBUS_SUPER_MASK |      \
+         IBUS_HYPER_MASK |      \
+         IBUS_META_MASK)
+
+#define CMSHM_FILTER(modifiers)  \
+    (modifiers & (CMSHM_MASK))
+
+/**
+ * process bopomofo
+ */
+inline gboolean
+BopomofoEditor::processBopomofo (guint keyval, guint keycode, guint modifiers)
+{
+    if (G_UNLIKELY (CMSHM_FILTER(modifiers) != 0))
+        return m_text ? TRUE : FALSE;
+
+    return insert (keyval);
+}
+
+void
+BopomofoEditor::updatePinyin (void)
+{
+    if (G_UNLIKELY (m_text.empty ())) {
+        m_pinyin.clear ();
+        m_pinyin_len = 0;
+    }
+    else {
+        bopomofo.clear();
+        for(String::iterator i = m_text.begin();i != m_text.end(); ++i) {
+            bopomofo += bopomofo_char[get_bopomofo_keyboard_map(*i)];
+        }
+
+        m_pinyin_len = PinyinParser::parse_bopomofo(bopomofo,            // bopomofo
+                                                    m_cursor,            // text length
+                                                    Config::option (),   // option
+                                                    m_pinyin,            // result
+                                                    MAX_PHRASE_LEN);     // max result length
+    }
+
+    updatePhraseEditor ();
+    update ();
+}
+
+void
+BopomofoEditor::updateAuxiliaryText (void)
+{
+    if (G_UNLIKELY (m_text.empty () ||
+        m_lookup_table.size () == 0)) {
+        hideAuxiliaryText ();
+        return;
+    }
+
+    m_buffer.clear ();
+
+    updateAuxiliaryTextBefore (m_buffer);
+
+    for (String::iterator i = m_text.begin();i!=m_text.end();i++) {
+        if (m_cursor == i - m_text.begin())
+            m_buffer << '|';
+        m_buffer.appendUnichar(bopomofo_char[get_bopomofo_keyboard_map(*i)]);
+    }
+    if (m_cursor == m_text.length())
+        m_buffer << '|';
+
+    updateAuxiliaryTextAfter (m_buffer);
+
+    StaticText aux_text (m_buffer);
+    Editor::updateAuxiliaryText (aux_text, TRUE);
+}
+
+void
+BopomofoEditor::commit (void)
+{
+    if (G_UNLIKELY (empty ()))
+        return;
+
+    m_buffer.clear ();
+
+    m_buffer << m_phrase_editor.selectedString ();
+
+    const gchar *p;
+
+    if (m_selected_special_phrase.empty ()) {
+        p = textAfterPinyin (m_buffer.utf8Length ());
+    }
+    else {
+        m_buffer << m_selected_special_phrase;
+        p = textAfterCursor ();
+    }
+
+    while (*p != '\0') {
+        m_buffer.appendUnichar ((gunichar)bopomofo_char[get_bopomofo_keyboard_map(*p++)]);
+    }
+
+    m_phrase_editor.commit ();
+    reset ();
+    PinyinEditor::commit ((const gchar *)m_buffer);
+}
+
+void
+BopomofoEditor::updatePreeditText (void)
+{
+    PinyinEditor::updatePreeditText();
+#if 0
+    /* preedit text = selected phrases + highlight candidate + rest text */
+    if (G_UNLIKELY (m_phrase_editor.empty () && m_text.empty ())) {
+        hidePreeditText ();
+        return;
+    }
+
+    guint edit_begin = 0;
+    guint edit_end = 0;
+
+    m_buffer.clear ();
+
+    /* add selected phrases */
+    m_buffer << m_phrase_editor.selectedString ();
+
+    if (G_UNLIKELY (! m_selected_special_phrase.empty ())) {
+        /* add selected special phrase */
+        m_buffer << m_selected_special_phrase;
+        edit_begin = m_buffer.utf8Length ();
+
+        /* append text after cursor */
+        m_buffer << textAfterCursor ();
+    }
+    else {
+        edit_begin = m_buffer.utf8Length ();
+        if (m_lookup_table.size () > 0) {
+            guint cursor = m_lookup_table.cursorPos ();
+
+            if (cursor < m_special_phrases.size ()) {
+                m_buffer << m_special_phrases[cursor].c_str ();
+                edit_end = m_buffer.utf8Length ();
+                /* append text after cursor */
+                m_buffer << textAfterCursor ();
+            }
+            else {
+                const Phrase & candidate = m_phrase_editor.candidate (cursor - m_special_phrases.size ());
+                if (m_text.size () == m_cursor) {
+                    /* cursor at end */
+                    if (m_props.modeSimp ())
+                        m_buffer << candidate;
+                    else
+                        SimpTradConverter::simpToTrad (candidate, m_buffer);
+                    edit_end = m_buffer.utf8Length ();
+
+                    /* append rest text */
+                    m_buffer << textAfterPinyin (edit_end);
+                }
+                else {
+                    guint candidate_end = edit_begin + candidate.len;
+                    m_buffer << m_pinyin[edit_begin]->sheng << m_pinyin[edit_begin]->yun;
+
+                    for (guint i = edit_begin + 1; i < candidate_end; i++) {
+                        m_buffer << ' ' << m_pinyin[i]->sheng << m_pinyin[i]->yun;
+                    }
+                    m_buffer << ' ' << textAfterPinyin (candidate_end);
+                    edit_end = m_buffer.utf8Length ();
+                }
+            }
+        }
+        else {
+            m_buffer << textAfterPinyin ();
+        }
+    }
+
+    StaticText preedit_text (m_buffer);
+    /* underline */
+    preedit_text.appendAttribute (IBUS_ATTR_TYPE_UNDERLINE, IBUS_ATTR_UNDERLINE_SINGLE, 0, -1);
+
+    /* candidate */
+    if (edit_begin < edit_end) {
+        preedit_text.appendAttribute (IBUS_ATTR_TYPE_FOREGROUND, 0x00000000,
+                                        edit_begin, edit_end);
+        preedit_text.appendAttribute (IBUS_ATTR_TYPE_BACKGROUND, 0x00c8c8f0,
+                                        edit_begin, edit_end);
+    }
+    Editor::updatePreeditText (preedit_text, edit_begin, TRUE);
+#endif
+}
+
+};
diff --git a/src/BopomofoEditor.h b/src/BopomofoEditor.h
new file mode 100644 (file)
index 0000000..9516233
--- /dev/null
@@ -0,0 +1,101 @@
+#ifndef __PY_BOPOMOFO_EDITOR_H_
+#define __PY_BOPOMOFO_EDITOR_H_
+
+#include "PinyinEditor.h"
+
+namespace PY {
+
+#include "Bopomofo.h"
+
+class BopomofoEditor : public PinyinEditor {
+
+public:
+    BopomofoEditor (PinyinProperties & props);
+    ~BopomofoEditor (void);
+
+public:
+    /* virtual functions */
+    virtual gboolean processKeyEvent (guint keyval, guint keycode, guint modifiers);
+    virtual void reset (void);
+
+protected:
+    std::wstring bopomofo;
+
+    virtual void updatePinyin (void);
+    virtual void updateAuxiliaryText (void);
+    virtual void updatePreeditText (void);
+    virtual void commit (void);
+
+    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);
+
+    gboolean processBopomofo (guint keyval, guint keycode, guint modifiers);
+
+    gint get_bopomofo_keyboard_map(gint ch) {
+        switch(ch){
+        case IBUS_1: return BOPOMOFO_B;
+        case IBUS_q: return BOPOMOFO_P;
+        case IBUS_a: return BOPOMOFO_M;
+        case IBUS_z: return BOPOMOFO_F;
+        case IBUS_2: return BOPOMOFO_D;
+        case IBUS_w: return BOPOMOFO_T;
+        case IBUS_s: return BOPOMOFO_N;
+        case IBUS_x: return BOPOMOFO_L;
+        case IBUS_e: return BOPOMOFO_G;
+        case IBUS_d: return BOPOMOFO_K;
+        case IBUS_c: return BOPOMOFO_H;
+        case IBUS_r: return BOPOMOFO_J;
+        case IBUS_f: return BOPOMOFO_Q;
+        case IBUS_v: return BOPOMOFO_X;
+        case IBUS_5: return BOPOMOFO_ZH;
+        case IBUS_t: return BOPOMOFO_CH;
+        case IBUS_g: return BOPOMOFO_SH;
+        case IBUS_b: return BOPOMOFO_R;
+        case IBUS_y: return BOPOMOFO_Z;
+        case IBUS_h: return BOPOMOFO_C;
+        case IBUS_n: return BOPOMOFO_S;
+
+        case IBUS_u: return BOPOMOFO_I;
+        case IBUS_j: return BOPOMOFO_U;
+        case IBUS_m: return BOPOMOFO_V;
+        case IBUS_8: return BOPOMOFO_A;
+        case IBUS_i: return BOPOMOFO_O;
+        case IBUS_k: return BOPOMOFO_E;
+        case IBUS_comma: return BOPOMOFO_E2;
+        case IBUS_9: return BOPOMOFO_AI;
+        case IBUS_o: return BOPOMOFO_EI;
+        case IBUS_l: return BOPOMOFO_AO;
+        case IBUS_period: return BOPOMOFO_OU;
+        case IBUS_0: return BOPOMOFO_AN;
+        case IBUS_p: return BOPOMOFO_EN;
+        case IBUS_semicolon: return BOPOMOFO_ANG;
+        case IBUS_slash: return BOPOMOFO_ENG;
+        case IBUS_minus: return BOPOMOFO_ER;
+
+        case IBUS_3: return BOPOMOFO_TONE_2;
+        case IBUS_4: return BOPOMOFO_TONE_3;
+        case IBUS_6: return BOPOMOFO_TONE_4;
+        case IBUS_7: return BOPOMOFO_TONE_5;
+
+        default:
+            return 0;
+        }
+    }
+
+
+};
+
+};
+
+#endif
index 3cd72e6..c86b82e 100644 (file)
@@ -34,6 +34,7 @@
 
 libexec_PROGRAMS = ibus-engine-pinyin
 ibus_engine_c_sources = \
+       BopomofoEditor.cc \
        Config.cc \
        Database.cc \
        DoublePinyinEditor.cc \
@@ -55,10 +56,12 @@ ibus_engine_c_sources = \
        SpecialPhraseTable.cc \
        $(NULL)
 ibus_engine_built_h_sources = \
+       Bopomofo.h \
        PinyinParserTable.h \
        SimpTradConverterTable.h \
        $(NULL)
 ibus_engine_h_sources = \
+       BopomofoEditor.h \
        Bus.h \
        Config.h \
        Database.h \
index 4e5bc3b..07fd16d 100644 (file)
@@ -325,6 +325,25 @@ PinyinEditor::processKeyEvent (guint keyval, guint keycode, guint modifiers)
     }
 }
 
+gboolean
+PinyinEditor::updateSpecialPhrases (void) {
+    if (!m_selected_special_phrase.empty ())
+        return FALSE;
+
+    guint size = m_special_phrases.size ();
+    guint begin = m_phrase_editor.cursorInChar ();
+    guint end = m_cursor;
+
+    m_special_phrases.clear ();
+    if (begin < end) {
+        SpecialPhraseTable::instance ().lookup (
+            m_text.substr (begin, m_cursor - begin),
+            m_special_phrases);
+    }
+
+    return size != m_special_phrases.size () || size != 0;
+}
+
 void
 PinyinEditor::updatePreeditText (void)
 {
index 1ae3fb0..d8a1c15 100644 (file)
@@ -39,37 +39,15 @@ protected:
     gboolean processSpace (guint keyval, guint keycode, guint modifiers);
     gboolean processOthers (guint keyval, guint keycode, guint modifiers);
 
-    void updatePreeditText (void);
-    void updateAuxiliaryText (void);
-    void updateLookupTable (void);
     gboolean fillLookupTableByPage (void);
 
     void updatePhraseEditor (void) { m_phrase_editor.update (m_pinyin); }
-
-    gboolean updateSpecialPhrases (void) {
-        if (!m_selected_special_phrase.empty ())
-            return FALSE;
-
-        guint size = m_special_phrases.size ();
-        guint begin = m_phrase_editor.cursorInChar ();
-        guint end = m_cursor;
-
-        m_special_phrases.clear ();
-        if (begin < end) {
-            SpecialPhraseTable::instance ().lookup (
-                m_text.substr (begin, m_cursor - begin),
-                m_special_phrases);
-        }
-
-        return size != m_special_phrases.size () || size != 0;
-    }
-
+    gboolean updateSpecialPhrases (void);
     gboolean selectCandidate (guint i);
     gboolean selectCandidateInPage (guint i);
     gboolean resetCandidate (guint i);
     gboolean resetCandidateInPage (guint i);
 
-    void commit (void);
     void commit (const gchar *str);
 
     const String & text (void) const { return m_text; }
@@ -89,6 +67,10 @@ protected:
     operator gboolean (void) const { return ! empty (); }
 
     /* virtual functions */
+    virtual void updatePreeditText (void);
+    virtual void updateAuxiliaryText (void);
+    virtual void updateLookupTable (void);
+    virtual void commit (void);
     virtual gboolean insert (gint ch) = 0;
     virtual gboolean removeCharBefore (void) = 0;
     virtual gboolean removeCharAfter (void) = 0;
index aa9f247..d279e66 100644 (file)
@@ -7,8 +7,10 @@
 #include "ExtEditor.h"
 #include "FullPinyinEditor.h"
 #include "DoublePinyinEditor.h"
+#include "BopomofoEditor.h"
 #include "PinyinEngine.h"
 #include "HalfFullConverter.h"
+#include "SimpTradConverter.h"
 #include "Config.h"
 #include "Text.h"
 #include "Util.h"
@@ -27,7 +29,8 @@ PinyinEngine::PinyinEngine (IBusEngine *engine)
     gint i;
     /* create editors */
     if (Config::doublePinyin ())
-        m_editors[MODE_INIT].reset (new DoublePinyinEditor (m_props));
+        //m_editors[MODE_INIT].reset (new DoublePinyinEditor (m_props));
+        m_editors[MODE_INIT].reset (new BopomofoEditor (m_props));
     else
         m_editors[MODE_INIT].reset (new FullPinyinEditor (m_props));
 
@@ -128,8 +131,10 @@ PinyinEngine::focusIn (void)
 {
     /* reset pinyin editor */
     if (Config::doublePinyin ()) {
-        if (dynamic_cast <DoublePinyinEditor *> (m_editors[MODE_INIT].get ()) == NULL) {
-            m_editors[MODE_INIT].reset (new DoublePinyinEditor (m_props));
+        //if (dynamic_cast <DoublePinyinEditor *> (m_editors[MODE_INIT].get ()) == NULL) {
+        //    m_editors[MODE_INIT].reset (new DoublePinyinEditor (m_props));
+        if (dynamic_cast <BopomofoEditor *> (m_editors[MODE_INIT].get ()) == NULL) {
+            m_editors[MODE_INIT].reset (new BopomofoEditor (m_props));
             connectEditorSignals (m_editors[MODE_INIT]);
         }
     }
index d6d1e3e..fe8e31b 100644 (file)
@@ -7,6 +7,7 @@
 
 namespace PY {
 
+#include "Bopomofo.h"
 #include "PinyinParserTable.h"
 
 static gboolean
@@ -260,5 +261,70 @@ PinyinParser::isPinyin (gint sheng, gint yun, guint option)
     return NULL;
 }
 
+static int
+bopomofo_cmp (const void *p1, const void *p2)
+{
+    const wchar_t *s1 = (wchar_t *) p1;
+    const Pinyin *s2 = *(const Pinyin **) p2;
+
+    return std::wcscmp (s1,s2->bopomofo);
+}
+
+gboolean
+PinyinParser::isBopomofoToneChar (const wchar_t ch)
+{
+    return ch == bopomofo_char[BOPOMOFO_TONE_2]
+        || ch == bopomofo_char[BOPOMOFO_TONE_3]
+        || ch == bopomofo_char[BOPOMOFO_TONE_4]
+        || ch == bopomofo_char[BOPOMOFO_TONE_5];
+}
+
+guint
+PinyinParser::parse_bopomofo (const std::wstring   &bopomofo,
+                             gint            len,
+                             guint           option,
+                             PinyinArray    &result,
+                             guint           max)
+{
+    std::wstring::const_iterator bpmf = bopomofo.begin();
+    const std::wstring::const_iterator end = bpmf + len;
+    const Pinyin **bs_res;
+    wchar_t buf[MAX_BOPOMOFO_LEN + 1];
+    gint i,j;
+
+    result.clear ();
+
+    if (G_UNLIKELY (len < 0))
+        len = bopomofo.length();
+
+    for (; bpmf < end && result.size () < max; ) {
+        for (i = MAX_BOPOMOFO_LEN; i>0; i--){
+            if (bpmf + i > end)
+                continue;
+
+            for (j=0;j<i;j++){
+                wchar_t key = *(bpmf+j);
+
+                if (j == i-1 && isBopomofoToneChar(key)) {
+                    break; /* ignore tone */
+                }
+
+                buf[j] = key;
+            }
+
+            buf[j] = '\0';
+            bs_res = (const Pinyin **) std::bsearch (buf, bopomofo_table,
+                                                  G_N_ELEMENTS (bopomofo_table),
+                                                  sizeof(bopomofo_table[0]),
+                                                  bopomofo_cmp);
+            if (G_UNLIKELY (bs_res != NULL))
+                break;
+        }
+        result.append(*bs_res,bpmf - bopomofo.begin() ,(*bs_res)->len);
+        bpmf += i;
+    }
+
+    return bpmf - bopomofo.begin();
 };
 
+};
index e27f24b..ebf0815 100644 (file)
@@ -16,6 +16,13 @@ public:
                         PinyinArray  &result,      // store pinyin in result
                         guint         max);        // max length of the result
     static const Pinyin * isPinyin (gint sheng, gint yun, guint option);
+    static guint parse_bopomofo (const std::wstring   &bopomofo,
+                                 gint            len,
+                                 guint           option,
+                                 PinyinArray    &result,
+                                 guint           max);
+    static gboolean isBopomofoToneChar (const wchar_t ch);
+
 };
 };
 #endif
index 6e175e2..8e7548f 100644 (file)
@@ -11438,4 +11438,3 @@ static const Pinyin *special_table[][4] = {
     { &pinyin_table[712],  &pinyin_table[125],  &pinyin_table[704],  &pinyin_table[357],  }, /* zun e => zu ne */
     { &pinyin_table[712],  &pinyin_table[126],  &pinyin_table[704],  &pinyin_table[359],  }, /* zun ei => zu nei */
 };
-